Can humans solve social navigation problems?
In the paper, we start by examining social navigation behaviors in a
one-day session (Study 1), or in the first session of a two-day study
(Studies 2-3). Across all three studies, the procedure is exactly
identical; studies 2-3 are, in this part of the dataset, exact
replications of study 1.
nav_study1 <- here("data", "clean-data", "study1_message_passing.csv") %>%
read_csv(show_col_types = FALSE) %>%
filter(
two_correct_options == FALSE,
shortest_path_given_opts == shortest_path_given_start_end
) %>%
mutate(
study = "Study 1",
measurement_id = str_c("D", measurement_id),
shortest_path = factor(shortest_path_given_opts)
) %>%
select(
study, sub_id, measurement_id, shortest_path,
startpoint_id, endpoint_id,
opt1_id, opt2_id,
correct_choice, sub_choice,
correct, rt
)
nav_study2 <- here("data", "clean-data", "study2_message_passing.csv") %>%
read_csv(show_col_types = FALSE) %>%
filter(
two_correct_options == FALSE,
shortest_path_given_opts == shortest_path_given_start_end
) %>%
mutate(
study = "Study 2",
measurement_id = case_when(
network == "learned" ~ str_c("D", measurement_id),
network == "reevaluated" ~ "D2b"
),
shortest_path = factor(shortest_path_given_opts)
) %>%
select(
study, sub_id, measurement_id, shortest_path,
startpoint_id, endpoint_id,
opt1_id, opt2_id,
correct_choice, sub_choice,
correct, rt
)
nav_study3 <- here("data", "clean-data", "study3_message_passing.csv") %>%
read_csv(show_col_types = FALSE) %>%
filter(
two_correct_options == FALSE,
shortest_path_given_opts == shortest_path_given_start_end
) %>%
mutate(
study = "Study 3",
measurement_id = case_when(
network == "reevaluated" ~ "D2b",
measurement_id == 1 ~ "D1",
measurement_id == 2 ~ "D1b",
measurement_id == 3 ~ "D2"
),
shortest_path = factor(shortest_path_given_opts)
) %>%
select(
study, sub_id, measurement_id, shortest_path,
startpoint_id, endpoint_id,
opt1_id, opt2_id,
correct_choice, sub_choice,
correct, rt
)
We’ll start off with some descriptive statistics of human behavior.
To maximize statistical power, we will pool across studies whenever
possible.
bind_rows(nav_study1, nav_study2, nav_study3) %>%
filter(measurement_id == "D1") %>%
group_by(measurement_id, shortest_path) %>%
summarise(accuracy = mean(correct), .groups = "drop") %>%
arrange(measurement_id, shortest_path) %>%
pivot_wider(
names_from = shortest_path, values_from = accuracy, names_prefix = "dist-"
) %>%
kbl(
caption = str_c(
"<center>", "Descriptive: Navigation accuracy", "</center>"
),
digits = 2
) %>%
kable_styling(bootstrap_options = c("responsive"))
Descriptive: Navigation accuracy
|
measurement_id
|
dist-2
|
dist-3
|
dist-4
|
|
D1
|
0.8
|
0.7
|
0.63
|
And now the inferential statistical tests. Note that we’re interested
in knowing whether navigation accuracy differs from chance at each
distance, so we’ll estimate the same statistical model multiple times,
changing the reference category each time. Note that this only
reparameterizes the model, such that the same variance is
accounted for by different parameters; it does not change the
total amount of variance accounted for.
nav_day1 <- bind_rows(nav_study1, nav_study2, nav_study3) %>%
filter(measurement_id == "D1") %>%
# Give every subject a distinct identifier
mutate(sub_id = str_c(study, " s", sub_id))
stats_nav_day1_dist2 <- nav_day1 %>%
mutate(shortest_path = fct_relevel(shortest_path, "2")) %>%
glmmTMB(
correct ~ shortest_path + (1 + shortest_path | sub_id) + (1 | study),
family = binomial,
data = .
)
stats_nav_day1_dist3 <- nav_day1 %>%
mutate(shortest_path = fct_relevel(shortest_path, "3")) %>%
glmmTMB(
correct ~ shortest_path + (1 + shortest_path | sub_id) + (1 | study),
family = binomial,
data = .
)
stats_nav_day1_dist4 <- nav_day1 %>%
mutate(shortest_path = fct_relevel(shortest_path, "4")) %>%
glmmTMB(
correct ~ shortest_path + (1 + shortest_path | sub_id) + (1 | study),
family = binomial,
data = .
)
map_dfr(
.x = list(
"dist-2" = stats_nav_day1_dist2,
"dist-3" = stats_nav_day1_dist3,
"dist-4" = stats_nav_day1_dist4
),
.f = ~tidy(.x, conf.int = TRUE),
.id = "ref_cat"
) %>%
check_significance() %>%
select(-c(ref_cat, effect, component)) %>%
kbl(
caption = str_c("<center>", "Navigation accuracy: Day 1", "</center>"),
digits = 3
) %>%
kable_styling(bootstrap_options = c("responsive")) %>%
pack_rows("Ref. Cat. dist-2", 1, 10) %>%
pack_rows("Ref. Cat. dist-3", 11, 20) %>%
pack_rows("Ref. Cat. dist-4", 21, 30)
Navigation accuracy: Day 1
|
group
|
term
|
estimate
|
std.error
|
statistic
|
p.value
|
conf.low
|
conf.high
|
sig
|
|
Ref. Cat. dist-2
|
|
NA
|
(Intercept)
|
1.682
|
0.118
|
14.303
|
0
|
1.451
|
1.912
|
***
|
|
NA
|
shortest_path3
|
-0.622
|
0.066
|
-9.428
|
0
|
-0.751
|
-0.493
|
***
|
|
NA
|
shortest_path4
|
-1.026
|
0.081
|
-12.710
|
0
|
-1.184
|
-0.868
|
***
|
|
sub_id
|
sd__(Intercept)
|
1.041
|
NA
|
NA
|
NA
|
0.897
|
1.208
|
|
|
sub_id
|
sd__shortest_path3
|
0.437
|
NA
|
NA
|
NA
|
0.320
|
0.596
|
|
|
sub_id
|
sd__shortest_path4
|
0.748
|
NA
|
NA
|
NA
|
0.624
|
0.897
|
|
|
sub_id
|
cor__(Intercept).shortest_path3
|
-0.392
|
NA
|
NA
|
NA
|
-0.645
|
-0.008
|
|
|
sub_id
|
cor__(Intercept).shortest_path4
|
-0.538
|
NA
|
NA
|
NA
|
-0.884
|
0.179
|
|
|
sub_id
|
cor__shortest_path3.shortest_path4
|
0.944
|
NA
|
NA
|
NA
|
0.236
|
0.976
|
|
|
study
|
sd__(Intercept)
|
0.122
|
NA
|
NA
|
NA
|
0.019
|
0.765
|
|
|
Ref. Cat. dist-3
|
|
NA
|
(Intercept)
|
1.059
|
0.114
|
9.335
|
0
|
0.837
|
1.282
|
***
|
|
NA
|
shortest_path2
|
0.622
|
0.066
|
9.428
|
0
|
0.493
|
0.751
|
***
|
|
NA
|
shortest_path4
|
-0.404
|
0.062
|
-6.549
|
0
|
-0.525
|
-0.283
|
***
|
|
sub_id
|
sd__(Intercept)
|
0.958
|
NA
|
NA
|
NA
|
0.807
|
1.137
|
|
|
sub_id
|
sd__shortest_path2
|
0.437
|
NA
|
NA
|
NA
|
0.320
|
0.596
|
|
|
sub_id
|
sd__shortest_path4
|
0.366
|
NA
|
NA
|
NA
|
0.243
|
0.549
|
|
|
sub_id
|
cor__(Intercept).shortest_path2
|
-0.030
|
NA
|
NA
|
NA
|
-0.398
|
0.351
|
|
|
sub_id
|
cor__(Intercept).shortest_path4
|
-0.352
|
NA
|
NA
|
NA
|
-0.364
|
0.248
|
|
|
sub_id
|
cor__shortest_path2.shortest_path4
|
-0.737
|
NA
|
NA
|
NA
|
-0.688
|
0.874
|
|
|
study
|
sd__(Intercept)
|
0.122
|
NA
|
NA
|
NA
|
0.019
|
0.765
|
|
|
Ref. Cat. dist-4
|
|
NA
|
(Intercept)
|
0.655
|
0.108
|
6.049
|
0
|
0.443
|
0.868
|
***
|
|
NA
|
shortest_path2
|
1.026
|
0.081
|
12.709
|
0
|
0.868
|
1.184
|
***
|
|
NA
|
shortest_path3
|
0.404
|
0.062
|
6.549
|
0
|
0.283
|
0.525
|
***
|
|
sub_id
|
sd__(Intercept)
|
0.897
|
NA
|
NA
|
NA
|
0.765
|
1.053
|
|
|
sub_id
|
sd__shortest_path2
|
0.748
|
NA
|
NA
|
NA
|
0.624
|
0.897
|
|
|
sub_id
|
sd__shortest_path3
|
0.366
|
NA
|
NA
|
NA
|
0.243
|
0.549
|
|
|
sub_id
|
cor__(Intercept).shortest_path2
|
-0.209
|
NA
|
NA
|
NA
|
-0.432
|
0.051
|
|
|
sub_id
|
cor__(Intercept).shortest_path3
|
-0.031
|
NA
|
NA
|
NA
|
-0.472
|
0.151
|
|
|
sub_id
|
cor__shortest_path2.shortest_path3
|
0.919
|
NA
|
NA
|
NA
|
-0.524
|
0.986
|
|
|
study
|
sd__(Intercept)
|
0.122
|
NA
|
NA
|
NA
|
0.019
|
0.765
|
|
We’ll plot out the raw data, plus model predictions…
predict_nav_day1 <- expand_grid(
measurement_id = "D1",
shortest_path = factor(2:4),
sub_id = NA, study = NA
) %>%
predict_glmmTMB(stats_nav_day1_dist2)
plot_nav_day1 <- bind_rows(nav_study2, nav_study3) %>%
filter(measurement_id == "D1") %>%
group_by(sub_id, measurement_id, shortest_path) %>%
summarise(accuracy = mean(correct), .groups = "drop") %>%
ggplot(aes(x=shortest_path, y=accuracy)) +
theme_custom() +
geom_hline(yintercept = 0.5, linetype = "dashed") +
geom_dotplot(
binwidth = 0.01,
binaxis = "y", stackdir = "center",
position = position_dodge(width = 0.75),
dotsize = 1, alpha = 0.5, color = NA,
show.legend = FALSE
) +
geom_pointrange(
aes(x = shortest_path, y = fit, ymin = fit - se.fit, ymax = fit + se.fit),
data = predict_nav_day1, inherit.aes = FALSE, show.legend = FALSE,
position = position_dodge(width = 0.15), linewidth = 1
) +
geom_line(
aes(x = shortest_path, y = fit, group = measurement_id),
data = predict_nav_day1, inherit.aes = FALSE,
position = position_dodge(width = 0.15), linewidth = 1
) +
scale_x_discrete(name = "Shortest path distance") +
scale_y_continuous(
name = "Accuracy", labels = scales::percent, breaks = seq(0, 1, 0.1)
) +
coord_cartesian(ylim = c(0.4, 1.1)) +
theme(legend.position = "bottom") +
ggtitle("Human social navigation")
plot_nav_day1

if (knitting) {
ggsave(
here("figures", str_c("navigation_day1", ".pdf")),
plot = plot_nav_day1,
width = 8/3, height = 3,
units = "in", dpi = 300
)
}
Computational models of social navigation
We’d like to have some mechanistic insights about how people solve
navigation problems. To do this, we’ll look at two candidate models of
navigation: breadth-first search (BFS) and the Successor Representation
(SR).
Simulations
BFS simulation
sim_bfs <- here("data", "bfs-sims", "bfs_sims_learned.csv") %>%
read_csv(show_col_types = FALSE) %>%
filter(
two_correct_options == FALSE,
shortest_path_given_opts == shortest_path_given_start_end
) %>%
mutate(shortest_path = factor(shortest_path_given_opts)) %>%
select(
shortest_path, startpoint_id, endpoint_id, opt1_id, opt2_id,
bfs_choice, bfs_correct_choice, bfs_n_visits_total
)
In our implementation, we model the BFS agent having some “threshold”
for searching through the network. This can be thought of as a
“willingness to spend time/effort performing a search” threshold. Once
that threshold is exceeded, it becomes increasingly likely that the
agent gives up and chooses randomly.
To see what threshold values might be informative to look at, we’ll
look at the average number of “searches” that an agent must perform to
make a (non-random) decision.
sim_bfs %>%
group_by(shortest_path) %>%
summarise(avg_n_searches = mean(bfs_n_visits_total)) %>%
kbl(
caption = str_c("<center>", "Average searches in online-BFS", "</center>"),
digits = 2
) %>%
kable_styling(bootstrap_options = c("responsive"))
Average searches in online-BFS
|
shortest_path
|
avg_n_searches
|
|
2
|
4.92
|
|
3
|
7.70
|
|
4
|
11.16
|
And now we’ll plot the model predictions…
bfs_avg_accuracy <- sim_bfs %>%
group_by(shortest_path, startpoint_id, endpoint_id, opt1_id, opt2_id) %>%
summarise(
bfs_accuracy = mean(bfs_correct_choice),
bfs_visits = mean(bfs_n_visits_total),
.groups = "drop"
)
plot_sim_bfs <- bfs_avg_accuracy %>%
expand_grid(search_threshold = seq(2, 12, 2)) %>%
rowwise() %>%
mutate(
# Note: p(BFS) is 1-p(give up)
p_bfs = softmax(
option_values = c(search_threshold, bfs_visits),
option_chosen = 1,
temperature = 1
)
) %>%
ungroup() %>%
# Weigh the model predictions according to their likelihood
mutate(
p_give_up = 1 - p_bfs,
bfs_threshold_accuracy = (p_bfs * bfs_accuracy) + (p_give_up * (1/2))
) %>%
# Format for plotting
mutate(
search_threshold = str_pad(search_threshold, width = 2, side = "left")
) %>%
bind_rows(
bfs_avg_accuracy %>%
mutate(
search_threshold = "Never gives up",
bfs_threshold_accuracy = bfs_accuracy
)
) %>%
# Now plot
ggplot(
aes(
x=shortest_path, y=bfs_threshold_accuracy,
color=search_threshold, group=search_threshold
)
) +
theme_custom() +
geom_hline(yintercept = 0.5, linetype = "dashed") +
stat_summary(geom = "line", fun = mean, linewidth = 1) +
scale_x_discrete(name = "Shortest path distance") +
scale_y_continuous(name = "Accuracy", labels = scales::percent) +
scale_color_viridis_d(
name = "Search threshold", option = "magma",
begin = 0.1, end = 0.9, direction = -1
) +
guides(color = guide_legend(byrow = TRUE, nrow = 1)) +
coord_cartesian(ylim = c(0.5, 1)) +
theme(
panel.grid = element_blank(),
legend.position = "bottom"
) +
ggtitle("Simulated BFS navigation")
plot_sim_bfs

if (knitting) {
ggsave(
here("figures", str_c("simulated_bfs", ".pdf")),
plot = plot_sim_bfs,
width = 8/3, height = 3,
units = "in", dpi = 300
)
}
SR navigation simulation
triallist_nav_learned <- nav_study1 %>%
filter(sub_id == 1) %>%
select(
startpoint_id, endpoint_id, opt1_id, opt2_id,
correct_choice, shortest_path
) %>%
arrange(startpoint_id, endpoint_id)
We’ll create some simulated learning observations.
set.seed(sum(utf8ToInt("Jenny and me was like peas and carrots")))
simulated_paired_associates <- adjlist %>%
filter(edge == 1) %>%
select(from, to) %>%
expand_grid(set = 1:5000, .) %>%
group_by(set) %>%
slice_sample(prop = 1) %>%
ungroup()
And now we’ll simulate an “asymptotic” SR and how it performs in the
navigation task.
simulate_sr <- function(simulated_observations) {
simulated_observations %>%
expand_grid(gamma = seq(0.1, 0.9, 0.1)) %>%
group_by(gamma) %>%
nest() %>%
mutate(
sr = map(
.x = data,
.f = ~build_rep_sr(
learning_data = .x, this_alpha = 0.1, this_gamma = gamma
)
)
) %>%
unnest(sr) %>%
ungroup() %>%
select(-data)
}
join_sr <- function(navigation_triallist, simulated_sr) {
navigation_triallist %>%
left_join(
simulated_sr %>%
rename(opt1_sr = sr_value, opt1_id = from, endpoint_id = to)
) %>%
left_join(
simulated_sr %>%
rename(opt2_sr = sr_value, opt2_id = from, endpoint_id = to)
)
}
sim_sr_matrix_asymptotic <- simulated_paired_associates %>%
simulate_sr()
sim_sr_behavior_asymptotic <- join_sr(
triallist_nav_learned, sim_sr_matrix_asymptotic
) %>%
# Feed values through softmax
mutate(across(c(opt1_sr, opt2_sr), ~.x * 100)) %>%
expand_grid(temperature = 1) %>%
rowwise() %>%
mutate(
p_correct = softmax(
option_values = c(opt1_sr, opt2_sr),
option_chosen = if_else(correct_choice == opt1_id, 1, 2),
temperature = temperature,
use_inverse_temperature = TRUE
)
) %>%
ungroup()
## Joining with `by = join_by(endpoint_id, opt1_id)`
## Warning in left_join(., simulated_sr %>% rename(opt1_sr = sr_value, opt1_id = from, : Detected an unexpected many-to-many relationship between `x` and `y`.
## ℹ Row 1 of `x` matches multiple rows in `y`.
## ℹ Row 45 of `y` matches multiple rows in `x`.
## ℹ If a many-to-many relationship is expected, set `relationship = "many-to-many"` to silence this
## warning.
## Joining with `by = join_by(endpoint_id, opt2_id, gamma)`
plot_sim_sr_asymptotic <- sim_sr_behavior_asymptotic %>%
mutate(
gamma = factor(gamma),
temperature = str_pad(temperature, width = 2, side = "left"),
temperature = str_c(unicode_greek["tau"], " = ", temperature)
) %>%
group_by(gamma, temperature, shortest_path) %>%
summarise(p_correct = mean(p_correct), .groups = "drop") %>%
ggplot(aes(x=shortest_path, y=p_correct, color=gamma)) +
theme_custom() +
facet_grid(rows = vars(temperature)) +
geom_hline(yintercept = 0.5, linetype = "dashed") +
geom_line(aes(color = gamma, group = gamma), linewidth = 0.8) +
scale_x_discrete(name = "Shortest path distance") +
scale_y_continuous(name = "Accuracy", labels = scales::percent) +
scale_color_viridis_d(
name = str_c(unicode_greek["gamma"], " = "), option = "turbo", end = 0.9
) +
guides(color = guide_legend(byrow = TRUE, nrow = 1)) +
coord_cartesian(ylim = c(0.5, 1)) +
theme(legend.position = "bottom") +
ggtitle("Simulated SR navigation")
plot_sim_sr_asymptotic

if (knitting) {
suppressWarnings(
ggsave(
here("figures", str_c("simulated_sr", ".pdf")),
plot = plot_sim_sr_asymptotic,
width = 8/3, height = 3,
units = "in", dpi = 300,
)
)
ggsave(
here("figures", str_c("simulated_sr_cairo", ".pdf")),
plot = plot_sim_sr_asymptotic +
guides(color = guide_legend(byrow = TRUE, nrow = 2)),
width = 8/3, height = 3,
units = "in", dpi = 300,
device = cairo_pdf
)
}
Model comparison
To do model comparison, we’ll need to pull in the estimated
parameters/likelihoods from the model-fitting.
clean_params_from_raw <- FALSE
if (clean_params_from_raw) {
params <- here("data", "param-fits") %>%
fs::dir_ls(regexp = "study[[:digit:]]_D[[:digit:]]b?") %>%
map_dfr(
.f = ~read_csv(.x, show_col_types = FALSE) %>%
best_optim_run("dataframe"),
.id = "filename"
) %>%
mutate(
study = str_extract(filename, "study[[:digit:]]"),
study = str_remove(study, "study"),
study = str_c("Study ", study),
measurement_id = str_extract(filename, "_D[[:digit:]]b?"),
measurement_id = str_remove(measurement_id, "_"),
sub_id = str_extract(filename, "sub-[[:digit:]]+"),
sub_id = str_remove(sub_id, "sub-"),
sub_id = as.integer(sub_id),
model = case_when(
str_detect(filename, "_hybrid-") ~ "hybrid",
str_detect(filename, "_sr-") ~ "sr",
str_detect(filename, "_bfs-") ~ "bfs"
)
) %>%
select(
study, sub_id, measurement_id,
model,
param_name, param_value = param_value_human_readable,
neg_loglik = optim_value
) %>%
arrange(study, sub_id, measurement_id, model)
params %>%
write_csv(here("data", "param-fits", "clean_param_fits.csv"))
} else {
params <- here("data", "param-fits", "clean_param_fits.csv") %>%
read_csv(show_col_types = FALSE)
}
source(here("code", "utils", "bayesian_model_selection.R"))
pxp_results <- params %>%
select(study, sub_id, measurement_id, model, neg_loglik) %>%
distinct() %>%
mutate(log_lik = -neg_loglik) %>%
select(-neg_loglik) %>%
pivot_wider(names_from = model, values_from = log_lik) %>%
select(-sub_id) %>%
group_by(study, measurement_id) %>%
nest() %>%
mutate(
test = map(
.x = data,
.f = ~bayesian_model_selection(.x)
)
) %>%
unnest(test) %>%
ungroup() %>%
select(-data)
pxp_results %>%
ggplot(aes(x=measurement_id, y=pxp, color=model)) +
theme_custom() +
facet_wrap(~study, scales = "free_x") +
geom_point(
position = position_dodge(width = 0.75)
)

pxp_results %>%
select(study, measurement_id, model, pxp) %>%
mutate(pxp = as.numeric(pxp)) %>%
pivot_wider(
names_from = model,
values_from = pxp,
names_prefix = "pxp_"
) %>%
kbl(
caption = str_c("<center>", "PXP results", "</center>"),
digits = 3
) %>%
kable_styling(bootstrap_options = c("responsive"))
PXP results
|
study
|
measurement_id
|
pxp_bfs
|
pxp_hybrid
|
pxp_sr
|
|
Study 1
|
D1
|
0
|
0.000
|
1.000
|
|
Study 2
|
D1
|
0
|
0.000
|
1.000
|
|
Study 2
|
D2
|
0
|
0.000
|
1.000
|
|
Study 3
|
D1
|
0
|
0.000
|
0.999
|
|
Study 3
|
D1b
|
0
|
0.000
|
1.000
|
|
Study 3
|
D2
|
0
|
0.006
|
0.994
|
Posterior predictive check
We’ll start by simulating the model’s predictions for each subject,
given their estimated parameters.
ppc_bfs <- bind_rows(nav_study1, nav_study2, nav_study3) %>%
filter(measurement_id %in% c("D1", "D2")) %>%
left_join(
params %>%
filter(model == "bfs") %>%
pivot_wider(names_from = param_name, values_from = param_value) %>%
select(study, sub_id, measurement_id, search_threshold, lapse_rate)
) %>%
left_join(bfs_avg_accuracy) %>%
mutate(
p_sub_choice_bfs = if_else(
sub_choice == correct_choice,
bfs_accuracy,
1 - bfs_accuracy
)
) %>%
# What's the probability of *completing* BFS-online all the way through?
rowwise() %>%
mutate(
search_threshold = search_threshold,
p_complete_bfs = softmax(
option_values = c(search_threshold, bfs_visits),
option_chosen = 1,
temperature = 1
)
) %>%
ungroup() %>%
# Weigh BFS predictions accordingly
mutate(
p_give_up = 1 - p_complete_bfs,
predicted_correct = (p_complete_bfs * p_sub_choice_bfs) + (p_give_up * 1/2),
### Add lapse rate
# Dividing by 2 is because there are two options to choose from
# Therefore, when lapse rate = 1, this becomes chance = 1/2
predicted_correct = predicted_correct * (1-lapse_rate) + (lapse_rate/2)
) %>%
# Average over trials
group_by(study, sub_id, measurement_id, shortest_path) %>%
summarise(
empirical = mean(correct),
predicted = mean(predicted_correct),
.groups = "drop"
)
## Joining with `by = join_by(study, sub_id, measurement_id)`
## Joining with `by = join_by(shortest_path, startpoint_id, endpoint_id, opt1_id, opt2_id)`
ppc_sr_matrix <- params %>%
filter(model == "sr") %>%
select(
study, sub_id, measurement_id, name = param_name, value = param_value
) %>%
pivot_wider() %>%
group_by(study, sub_id, measurement_id) %>%
nest() %>%
mutate(
sim_sr = map(
.x = data,
.f = ~build_rep_sr(
learning_data = simulated_paired_associates %>% filter(set %in% 1:100),
this_alpha = 0.1,
this_gamma = .x$sr_gamma,
bidirectional = TRUE
)
)
) %>%
unnest(sim_sr) %>%
unnest(data) %>%
ungroup()
ppc_sr_behavior <- bind_rows(nav_study1, nav_study2, nav_study3) %>%
filter(measurement_id %in% c("D1", "D2")) %>%
left_join(
ppc_sr_matrix %>%
rename(opt1_id = from, endpoint_id = to, opt1_sr = sr_value)
) %>%
left_join(
ppc_sr_matrix %>%
rename(opt2_id = from, endpoint_id = to, opt2_sr = sr_value)
) %>%
rowwise() %>%
mutate(
predicted_correct = softmax(
option_values = c(opt1_sr, opt2_sr) * 100,
option_chosen = if_else(correct_choice == opt1_id, 1, 2),
temperature = softmax_temperature,
use_inverse_temperature = TRUE,
lapse_rate = lapse_rate
)
) %>%
ungroup() %>%
# Fix trials when the softmax becomes undefined
mutate(
predicted_correct = case_when(
is.nan(predicted_correct) & (sub_choice == correct_choice) ~ 1,
is.nan(predicted_correct) & (sub_choice != correct_choice) ~ 0,
TRUE ~ predicted_correct
)
) %>%
# Average over trials
group_by(study, sub_id, measurement_id, shortest_path) %>%
summarise(
empirical = mean(correct),
predicted = mean(predicted_correct),
.groups = "drop"
)
## Joining with `by = join_by(study, sub_id, measurement_id, endpoint_id, opt1_id)`
## Joining with `by = join_by(study, sub_id, measurement_id, endpoint_id, opt2_id, sr_gamma,
## softmax_temperature, lapse_rate)`
Now that we have both PPCs, we can plot them side-by-side.
plot_ppc_day1 <- ppc_bfs %>%
rename(predicted_bfs = predicted) %>%
left_join(ppc_sr_behavior %>% rename(predicted_sr = predicted)) %>%
pivot_longer(
c(empirical, predicted_bfs, predicted_sr),
names_to = "agent", values_to = "accuracy"
) %>%
filter(measurement_id == "D1") %>%
ggplot(aes(x=shortest_path, y=accuracy)) +
theme_custom() +
geom_hline(yintercept = 0.5, linetype = "dashed") +
geom_point(
aes(color = agent),
alpha = 0.05,
position = position_jitterdodge(
jitter.width = 0.2, jitter.height = 0, dodge.width = 0.75, seed = 1
),
show.legend = FALSE
) +
stat_summary(
aes(color = agent), geom = "crossbar", fun = mean,
position = position_dodge(0.5)
) +
scale_x_discrete(name = "Shortest path distance") +
scale_y_continuous(
name = "Accuracy", labels = scales::percent, breaks = seq(0, 1, 0.25)
) +
scale_color_manual(
name = NULL,
values = c(
"empirical"="#fd8d3c",
"predicted_bfs"="#8c2d04",
"predicted_sr"="#bd0026"
),
labels = c("empirical"="Human", "predicted_bfs"="BFS", "predicted_sr"="SR")
) +
theme(legend.position = "bottom") +
ggtitle("Posterior predictive check")
## Joining with `by = join_by(study, sub_id, measurement_id, shortest_path,
## empirical)`
plot_ppc_day1

if (knitting) {
ggsave(
here("figures", str_c("ppc_day1", ".pdf")),
plot = plot_ppc_day1,
width = 8/2, height = 2.5,
units = "in", dpi = 300
)
}
Held-out trials
There were some trials where both Sources had equivalent shortest
path distances from the Target. We would expect that BFS would be
largely indifferent between the two Sources, but it is possible that
humans and/or the SR would make other predictions.
nav_study1_ties <- here("data", "clean-data", "study1_message_passing.csv") %>%
read_csv(show_col_types = FALSE) %>%
filter(
two_correct_options == TRUE,
shortest_path_given_opts == shortest_path_given_start_end
) %>%
mutate(
study = "Study 1",
measurement_id = str_c("D", measurement_id),
shortest_path = factor(shortest_path_given_opts)
) %>%
select(
study, sub_id, measurement_id, shortest_path,
startpoint_id, endpoint_id,
opt1_id, opt2_id,
correct_choice, sub_choice,
correct, rt
) %>%
filter(measurement_id %in% c("D1", "D2"))
nav_study2_ties <- here("data", "clean-data", "study2_message_passing.csv") %>%
read_csv(show_col_types = FALSE) %>%
filter(
two_correct_options == TRUE,
shortest_path_given_opts == shortest_path_given_start_end
) %>%
mutate(
study = "Study 2",
measurement_id = case_when(
network == "learned" ~ str_c("D", measurement_id),
network == "reevaluated" ~ "D2b"
),
shortest_path = factor(shortest_path_given_opts)
) %>%
select(
study, sub_id, measurement_id, shortest_path,
startpoint_id, endpoint_id,
opt1_id, opt2_id,
correct_choice, sub_choice,
correct, rt
) %>%
filter(measurement_id %in% c("D1", "D2"))
nav_study3_ties <- here("data", "clean-data", "study3_message_passing.csv") %>%
read_csv(show_col_types = FALSE) %>%
filter(
two_correct_options == TRUE,
shortest_path_given_opts == shortest_path_given_start_end
) %>%
mutate(
study = "Study 3",
measurement_id = case_when(
network == "reevaluated" ~ "D2b",
measurement_id == 1 ~ "D1",
measurement_id == 2 ~ "D1b",
measurement_id == 3 ~ "D2"
),
shortest_path = factor(shortest_path_given_opts)
) %>%
select(
study, sub_id, measurement_id, shortest_path,
startpoint_id, endpoint_id,
opt1_id, opt2_id,
correct_choice, sub_choice,
correct, rt
) %>%
filter(measurement_id %in% c("D1", "D2"))
tie_item_analysis_humans <- bind_rows(
nav_study1_ties, nav_study2_ties, nav_study3_ties
) %>%
filter(measurement_id == "D1") %>%
group_by(shortest_path, startpoint_id, endpoint_id, opt1_id, opt2_id) %>%
summarise(
p_human_opt1 = mean(sub_choice == opt1_id),
.groups = "drop"
)
bfs_avg_accuracy_ties <- here("data", "bfs-sims", "bfs_sims_learned.csv") %>%
read_csv(show_col_types = FALSE) %>%
filter(
two_correct_options == TRUE,
shortest_path_given_opts == shortest_path_given_start_end
) %>%
mutate(shortest_path = factor(shortest_path_given_opts)) %>%
select(
shortest_path, startpoint_id, endpoint_id, opt1_id, opt2_id,
bfs_choice, bfs_correct_choice, bfs_n_visits_total
) %>%
group_by(shortest_path, startpoint_id, endpoint_id, opt1_id, opt2_id) %>%
summarise(
p_bfs_opt1 = mean(bfs_choice == opt1_id),
bfs_visits = mean(bfs_n_visits_total),
.groups = "drop"
)
tie_item_analysis_bfs <- bind_rows(
nav_study1_ties, nav_study2_ties, nav_study3_ties
) %>%
filter(measurement_id == "D1") %>%
left_join(
params %>%
filter(model == "bfs") %>%
pivot_wider(names_from = param_name, values_from = param_value) %>%
select(study, sub_id, measurement_id, search_threshold, lapse_rate)
) %>%
left_join(bfs_avg_accuracy_ties) %>%
mutate(
p_sub_choice_bfs = if_else(
sub_choice == opt1_id,
p_bfs_opt1,
1 - p_bfs_opt1
)
) %>%
select(-p_bfs_opt1) %>%
# What's the probability of *completing* BFS-online all the way through?
rowwise() %>%
mutate(
search_threshold = search_threshold,
p_complete_bfs = softmax(
option_values = c(search_threshold, bfs_visits),
option_chosen = 1,
temperature = 1
)
) %>%
ungroup() %>%
# Weigh BFS predictions accordingly
mutate(
p_give_up = 1 - p_complete_bfs,
p_bfs_opt1 = (p_complete_bfs * p_sub_choice_bfs) + (p_give_up * 1/2),
### Add lapse rate
# Dividing by 2 is because there are two options to choose from
# Therefore, when lapse rate = 1, this becomes chance = 1/2
p_bfs_opt1 = p_bfs_opt1 * (1-lapse_rate) + (lapse_rate/2)
) %>%
# Average over trials
# group_by(shortest_path) %>%
group_by(shortest_path, startpoint_id, endpoint_id, opt1_id, opt2_id) %>%
summarise(
p_bfs_opt1 = mean(p_bfs_opt1),
.groups = "drop"
)
## Joining with `by = join_by(study, sub_id, measurement_id)`
## Joining with `by = join_by(shortest_path, startpoint_id, endpoint_id, opt1_id, opt2_id)`
tie_item_analysis_sr <- bind_rows(
nav_study1_ties, nav_study2_ties, nav_study3_ties
) %>%
filter(measurement_id == "D1") %>%
left_join(
ppc_sr_matrix %>%
select(
study, sub_id, measurement_id,
opt1_id = from,
endpoint_id = to,
opt1_sr = sr_value
)
) %>%
left_join(
ppc_sr_matrix %>%
select(
study, sub_id, measurement_id,
opt2_id = from,
endpoint_id = to,
opt2_sr = sr_value,
sr_gamma, softmax_temperature, lapse_rate
)
) %>%
rowwise() %>%
mutate(
p_sr_opt1 = softmax(
option_values = c(opt1_sr, opt2_sr) * 100,
option_chosen = 1,
temperature = softmax_temperature,
use_inverse_temperature = TRUE,
lapse_rate = lapse_rate
)
) %>%
group_by(shortest_path, startpoint_id, endpoint_id, opt1_id, opt2_id) %>%
summarise(
p_sr_opt1 = mean(p_sr_opt1, na.rm = TRUE),
.groups = "drop"
)
## Joining with `by = join_by(study, sub_id, measurement_id, endpoint_id, opt1_id)`
## Joining with `by = join_by(study, sub_id, measurement_id, endpoint_id, opt2_id)`
plot_ties <- tie_item_analysis_humans %>%
left_join(tie_item_analysis_bfs) %>%
left_join(tie_item_analysis_sr) %>%
mutate(item = row_number(), item = factor(item)) %>%
pivot_longer(
starts_with("p_"),
names_to = "agent",
values_to = "p_choose_opt1"
) %>%
mutate(
agent = str_remove_all(agent, "p_|_opt1"),
agent = case_when(
agent == "human" ~ "Human",
agent == "sr" ~ "SR",
agent == "bfs" ~ "BFS",
),
agent = fct_relevel(agent, "Human", "SR")
) %>%
ggplot(aes(x=shortest_path, y=p_choose_opt1)) +
theme_custom() +
facet_wrap(~agent) +
geom_hline(yintercept = 0.5, linetype = "dashed") +
geom_point(alpha = 0.25) +
stat_summary(geom = "crossbar", fun = mean, color = "red") +
scale_x_discrete(name = "Shortest path distance") +
scale_y_continuous(
name = "p(Choose Source A > B)",
labels = scales::percent, breaks = seq(0, 1, 0.25)
) +
theme(
panel.grid = element_blank(),
legend.position = "bottom"
) +
ggtitle("Navigation problems with two correct answers")
## Joining with `by = join_by(shortest_path, startpoint_id, endpoint_id, opt1_id, opt2_id)`
## Joining with `by = join_by(shortest_path, startpoint_id, endpoint_id, opt1_id, opt2_id)`
plot_ties

if (knitting) {
ggsave(
here("figures", str_c("navigation_heldout_day1", ".pdf")),
plot = plot_ties,
width = 8/2, height = 2.5,
units = "in", dpi = 300
)
}
Does navigation improve after rest?
First, some descriptives…
bind_rows(nav_study1, nav_study2, nav_study3) %>%
group_by(measurement_id, shortest_path) %>%
summarise(accuracy = mean(correct), .groups = "drop") %>%
arrange(measurement_id, shortest_path) %>%
pivot_wider(
names_from = shortest_path, values_from = accuracy, names_prefix = "dist-"
) %>%
kbl(
caption = str_c(
"<center>", "Descriptive: Navigation accuracy", "</center>"
),
digits = 2
) %>%
kable_styling(bootstrap_options = c("responsive"))
Descriptive: Navigation accuracy
|
measurement_id
|
dist-2
|
dist-3
|
dist-4
|
|
D1
|
0.80
|
0.70
|
0.63
|
|
D1b
|
0.79
|
0.72
|
0.68
|
|
D2
|
0.82
|
0.75
|
0.71
|
|
D2b
|
0.81
|
0.72
|
0.62
|
Overnight rest
Now we want to see how navigation accuracy changes from day 1 to day
2. This pools across studies 2-3 (study 1 was only a one-day
experiment).
nav_day1_to_day2 <- bind_rows(nav_study2, nav_study3) %>%
filter(measurement_id %in% c("D1", "D2")) %>%
# Give every subject a distinct identifier
mutate(sub_id = str_c(study, " s", sub_id))
stats_nav_day2_dist2 <- nav_day1_to_day2 %>%
mutate(shortest_path = fct_relevel(shortest_path, "2")) %>%
glmmTMB(
correct ~ shortest_path * measurement_id +
(1 + shortest_path + measurement_id | sub_id) + (1 | study),
family = binomial,
data = .
)
stats_nav_day2_dist3 <- nav_day1_to_day2 %>%
mutate(shortest_path = fct_relevel(shortest_path, "3")) %>%
glmmTMB(
correct ~ shortest_path * measurement_id +
(1 + shortest_path + measurement_id | sub_id) + (1 | study),
family = binomial,
data = .
)
stats_nav_day2_dist4 <- nav_day1_to_day2 %>%
mutate(shortest_path = fct_relevel(shortest_path, "4")) %>%
glmmTMB(
correct ~ shortest_path * measurement_id +
(1 + shortest_path + measurement_id | sub_id) + (1 | study),
family = binomial,
data = .
)
map_dfr(
.x = list(
"dist-2" = stats_nav_day2_dist2,
"dist-3" = stats_nav_day2_dist3,
"dist-4" = stats_nav_day2_dist4
),
.f = ~tidy(.x, conf.int = TRUE),
.id = "ref_cat"
) %>%
check_significance() %>%
select(-c(ref_cat, effect, component)) %>%
kbl(
caption = str_c(
"<center>", "Navigation accuracy: Day 1 to Day 2", "</center>"
),
digits = 3
) %>%
kable_styling(bootstrap_options = c("responsive")) %>%
pack_rows("Ref. Cat. dist-2", 1, 17) %>%
pack_rows("Ref. Cat. dist-3", 18, 34) %>%
pack_rows("Ref. Cat. dist-4", 35, 51)
Navigation accuracy: Day 1 to Day 2
|
group
|
term
|
estimate
|
std.error
|
statistic
|
p.value
|
conf.low
|
conf.high
|
sig
|
|
Ref. Cat. dist-2
|
|
NA
|
(Intercept)
|
1.765
|
0.114
|
15.476
|
0.000
|
1.541
|
1.988
|
***
|
|
NA
|
shortest_path3
|
-0.452
|
0.083
|
-5.452
|
0.000
|
-0.615
|
-0.290
|
***
|
|
NA
|
shortest_path4
|
-0.959
|
0.091
|
-10.554
|
0.000
|
-1.137
|
-0.781
|
***
|
|
NA
|
measurement_idD2
|
0.234
|
0.080
|
2.906
|
0.004
|
0.076
|
0.391
|
**
|
|
NA
|
shortest_path3:measurement_idD2
|
0.030
|
0.087
|
0.351
|
0.725
|
-0.139
|
0.200
|
|
|
NA
|
shortest_path4:measurement_idD2
|
0.196
|
0.083
|
2.356
|
0.018
|
0.033
|
0.359
|
|
|
sub_id
|
sd__(Intercept)
|
1.024
|
NA
|
NA
|
NA
|
0.858
|
1.223
|
|
|
sub_id
|
sd__shortest_path3
|
0.461
|
NA
|
NA
|
NA
|
0.334
|
0.635
|
|
|
sub_id
|
sd__shortest_path4
|
0.634
|
NA
|
NA
|
NA
|
0.512
|
0.785
|
|
|
sub_id
|
sd__measurement_idD2
|
0.483
|
NA
|
NA
|
NA
|
0.370
|
0.631
|
|
|
sub_id
|
cor__(Intercept).shortest_path3
|
0.182
|
NA
|
NA
|
NA
|
-0.175
|
0.481
|
|
|
sub_id
|
cor__(Intercept).shortest_path4
|
-0.250
|
NA
|
NA
|
NA
|
-0.799
|
0.057
|
|
|
sub_id
|
cor__(Intercept).measurement_idD2
|
0.451
|
NA
|
NA
|
NA
|
-0.037
|
0.608
|
|
|
sub_id
|
cor__shortest_path3.shortest_path4
|
0.808
|
NA
|
NA
|
NA
|
0.311
|
0.873
|
|
|
sub_id
|
cor__shortest_path3.measurement_idD2
|
0.466
|
NA
|
NA
|
NA
|
-0.116
|
0.837
|
|
|
sub_id
|
cor__shortest_path4.measurement_idD2
|
0.007
|
NA
|
NA
|
NA
|
-0.520
|
0.712
|
|
|
study
|
sd__(Intercept)
|
0.000
|
NA
|
NA
|
NA
|
0.000
|
Inf
|
|
|
Ref. Cat. dist-3
|
|
NA
|
(Intercept)
|
1.312
|
0.134
|
9.810
|
0.000
|
1.050
|
1.574
|
***
|
|
NA
|
shortest_path2
|
0.452
|
0.083
|
5.452
|
0.000
|
0.290
|
0.615
|
***
|
|
NA
|
shortest_path4
|
-0.507
|
0.079
|
-6.411
|
0.000
|
-0.662
|
-0.352
|
***
|
|
NA
|
measurement_idD2
|
0.264
|
0.088
|
2.989
|
0.003
|
0.091
|
0.437
|
**
|
|
NA
|
shortest_path2:measurement_idD2
|
-0.030
|
0.087
|
-0.351
|
0.725
|
-0.200
|
0.139
|
|
|
NA
|
shortest_path4:measurement_idD2
|
0.166
|
0.090
|
1.833
|
0.067
|
-0.011
|
0.343
|
.
|
|
sub_id
|
sd__(Intercept)
|
1.197
|
NA
|
NA
|
NA
|
0.997
|
1.437
|
|
|
sub_id
|
sd__shortest_path2
|
0.461
|
NA
|
NA
|
NA
|
0.334
|
0.635
|
|
|
sub_id
|
sd__shortest_path4
|
0.377
|
NA
|
NA
|
NA
|
0.266
|
0.536
|
|
|
sub_id
|
sd__measurement_idD2
|
0.483
|
NA
|
NA
|
NA
|
0.370
|
0.631
|
|
|
sub_id
|
cor__(Intercept).shortest_path2
|
-0.541
|
NA
|
NA
|
NA
|
-0.743
|
-0.174
|
|
|
sub_id
|
cor__(Intercept).shortest_path4
|
-0.497
|
NA
|
NA
|
NA
|
-0.605
|
0.049
|
|
|
sub_id
|
cor__(Intercept).measurement_idD2
|
0.565
|
NA
|
NA
|
NA
|
-0.045
|
0.827
|
|
|
sub_id
|
cor__shortest_path2.shortest_path4
|
-0.137
|
NA
|
NA
|
NA
|
-0.002
|
0.234
|
|
|
sub_id
|
cor__shortest_path2.measurement_idD2
|
-0.466
|
NA
|
NA
|
NA
|
-0.209
|
0.025
|
|
|
sub_id
|
cor__shortest_path4.measurement_idD2
|
-0.557
|
NA
|
NA
|
NA
|
-0.093
|
0.401
|
|
|
study
|
sd__(Intercept)
|
0.000
|
NA
|
NA
|
NA
|
0.000
|
Inf
|
|
|
Ref. Cat. dist-4
|
|
NA
|
(Intercept)
|
0.805
|
0.118
|
6.827
|
0.000
|
0.574
|
1.037
|
***
|
|
NA
|
shortest_path2
|
0.959
|
0.091
|
10.554
|
0.000
|
0.781
|
1.137
|
***
|
|
NA
|
shortest_path3
|
0.507
|
0.079
|
6.411
|
0.000
|
0.352
|
0.662
|
***
|
|
NA
|
measurement_idD2
|
0.430
|
0.083
|
5.174
|
0.000
|
0.267
|
0.592
|
***
|
|
NA
|
shortest_path2:measurement_idD2
|
-0.196
|
0.083
|
-2.356
|
0.018
|
-0.359
|
-0.033
|
|
|
NA
|
shortest_path3:measurement_idD2
|
-0.166
|
0.090
|
-1.834
|
0.067
|
-0.343
|
0.011
|
.
|
|
sub_id
|
sd__(Intercept)
|
1.061
|
NA
|
NA
|
NA
|
0.883
|
1.276
|
|
|
sub_id
|
sd__shortest_path2
|
0.634
|
NA
|
NA
|
NA
|
0.512
|
0.785
|
|
|
sub_id
|
sd__shortest_path3
|
0.377
|
NA
|
NA
|
NA
|
0.265
|
0.536
|
|
|
sub_id
|
sd__measurement_idD2
|
0.483
|
NA
|
NA
|
NA
|
0.370
|
0.631
|
|
|
sub_id
|
cor__(Intercept).shortest_path2
|
-0.356
|
NA
|
NA
|
NA
|
-0.587
|
-0.038
|
|
|
sub_id
|
cor__(Intercept).shortest_path3
|
0.205
|
NA
|
NA
|
NA
|
-0.465
|
0.400
|
|
|
sub_id
|
cor__(Intercept).measurement_idD2
|
0.439
|
NA
|
NA
|
NA
|
-0.096
|
0.450
|
|
|
sub_id
|
cor__shortest_path2.shortest_path3
|
0.695
|
NA
|
NA
|
NA
|
0.448
|
0.848
|
|
|
sub_id
|
cor__shortest_path2.measurement_idD2
|
-0.007
|
NA
|
NA
|
NA
|
-0.118
|
0.214
|
|
|
sub_id
|
cor__shortest_path3.measurement_idD2
|
0.557
|
NA
|
NA
|
NA
|
-0.497
|
0.628
|
|
|
study
|
sd__(Intercept)
|
0.000
|
NA
|
NA
|
NA
|
0.000
|
Inf
|
|
predict_nav_day1_to_day2 <- expand_grid(
measurement_id = c("D1", "D2"),
shortest_path = factor(2:4),
sub_id = NA, study = NA
) %>%
predict_glmmTMB(stats_nav_day2_dist2)
plot_nav_day1_to_day2 <- nav_day1_to_day2 %>%
group_by(sub_id, measurement_id, shortest_path) %>%
summarise(accuracy = mean(correct), .groups = "drop") %>%
ggplot(aes(x=shortest_path, y=accuracy, color=measurement_id)) +
theme_custom() +
geom_hline(yintercept = 0.5, linetype = "dashed") +
geom_dotplot(
aes(fill = measurement_id),
binwidth = 0.01,
binaxis = "y", stackdir = "center",
position = position_dodge(width = 0.75),
dotsize = 1, alpha = 0.5, color = NA,
show.legend = FALSE
) +
geom_pointrange(
aes(
x = shortest_path, y = fit,
ymin = fit - se.fit, ymax = fit + se.fit,
color = measurement_id
),
data = predict_nav_day1_to_day2, inherit.aes = FALSE, show.legend = FALSE,
position = position_dodge(width = 0.15), linewidth = 1
) +
geom_line(
aes(
x = shortest_path, y = fit,
group = measurement_id, color = measurement_id
),
data = predict_nav_day1_to_day2, inherit.aes = FALSE,
position = position_dodge(width = 0.15), linewidth = 1
) +
scale_x_discrete(name = "Shortest path distance") +
scale_y_continuous(
name = "Accuracy", labels = scales::percent, breaks = seq(0, 1, 0.25)
) +
scale_color_manual(
name = "Measurement",
values = c("D1"="#fa9fb5", "D2"="#7a0177"),
labels = c("D1"="Before overnight rest", "D2"="After overnight rest")
) +
scale_fill_manual(values = c("D1"="#fa9fb5", "D2"="#7a0177")) +
coord_cartesian(ylim = c(0.3, 1.1)) +
theme(legend.position = "bottom") +
ggtitle("Navigation after overnight rest")
plot_nav_day1_to_day2

if (knitting) {
ggsave(
here("figures", str_c("navigation_day1_to_day2", ".pdf")),
plot = plot_nav_day1_to_day2,
width = 4, height = 3,
units = "in", dpi = 300
)
}
Awake rest
Is a brief period of awake rest sufficient for improving navigation
accuracy?
stats_nav_awake_dist2 <- nav_study3 %>%
filter(measurement_id %in% c("D1", "D1b")) %>%
mutate(shortest_path = fct_relevel(shortest_path, "2")) %>%
glmmTMB(
correct ~ shortest_path * measurement_id +
(1 + shortest_path + measurement_id | sub_id),
family = binomial,
data = .
)
stats_nav_awake_dist3 <- nav_study3 %>%
filter(measurement_id %in% c("D1", "D1b")) %>%
mutate(shortest_path = fct_relevel(shortest_path, "3")) %>%
glmmTMB(
correct ~ shortest_path * measurement_id +
(1 + shortest_path + measurement_id | sub_id),
family = binomial,
data = .
)
stats_nav_awake_dist4 <- nav_study3 %>%
filter(measurement_id %in% c("D1", "D1b")) %>%
mutate(shortest_path = fct_relevel(shortest_path, "4")) %>%
glmmTMB(
correct ~ shortest_path * measurement_id +
(1 + shortest_path + measurement_id | sub_id),
family = binomial,
data = .
)
map_dfr(
.x = list(
"dist-2" = stats_nav_awake_dist2,
"dist-3" = stats_nav_awake_dist3,
"dist-4" = stats_nav_awake_dist4
),
.f = ~tidy(.x, conf.int = TRUE),
.id = "ref_cat"
) %>%
check_significance() %>%
select(-c(ref_cat, effect, component)) %>%
kbl(
caption = str_c("<center>", "Navigation accuracy: Awake Rest", "</center>"),
digits = 3
) %>%
kable_styling(bootstrap_options = c("responsive")) %>%
pack_rows("Ref. Cat. dist-2", 1, 16) %>%
pack_rows("Ref. Cat. dist-3", 17, 32) %>%
pack_rows("Ref. Cat. dist-4", 33, 48)
Navigation accuracy: Awake Rest
|
group
|
term
|
estimate
|
std.error
|
statistic
|
p.value
|
conf.low
|
conf.high
|
sig
|
|
Ref. Cat. dist-2
|
|
NA
|
(Intercept)
|
1.840
|
0.193
|
9.542
|
0.000
|
1.462
|
2.218
|
***
|
|
NA
|
shortest_path3
|
-0.424
|
0.129
|
-3.290
|
0.001
|
-0.677
|
-0.171
|
**
|
|
NA
|
shortest_path4
|
-0.936
|
0.134
|
-6.972
|
0.000
|
-1.199
|
-0.673
|
***
|
|
NA
|
measurement_idD1b
|
-0.058
|
0.122
|
-0.475
|
0.635
|
-0.296
|
0.181
|
|
|
NA
|
shortest_path3:measurement_idD1b
|
0.022
|
0.123
|
0.175
|
0.861
|
-0.220
|
0.263
|
|
|
NA
|
shortest_path4:measurement_idD1b
|
0.244
|
0.119
|
2.060
|
0.039
|
0.012
|
0.477
|
|
|
sub_id
|
sd__(Intercept)
|
1.216
|
NA
|
NA
|
NA
|
0.947
|
1.561
|
|
|
sub_id
|
sd__shortest_path3
|
0.518
|
NA
|
NA
|
NA
|
0.352
|
0.764
|
|
|
sub_id
|
sd__shortest_path4
|
0.632
|
NA
|
NA
|
NA
|
0.465
|
0.859
|
|
|
sub_id
|
sd__measurement_idD1b
|
0.544
|
NA
|
NA
|
NA
|
0.395
|
0.751
|
|
|
sub_id
|
cor__(Intercept).shortest_path3
|
-0.019
|
NA
|
NA
|
NA
|
-0.462
|
0.435
|
|
|
sub_id
|
cor__(Intercept).shortest_path4
|
-0.262
|
NA
|
NA
|
NA
|
-0.840
|
0.127
|
|
|
sub_id
|
cor__(Intercept).measurement_idD1b
|
0.045
|
NA
|
NA
|
NA
|
-0.264
|
0.378
|
|
|
sub_id
|
cor__shortest_path3.shortest_path4
|
0.845
|
NA
|
NA
|
NA
|
0.444
|
0.913
|
|
|
sub_id
|
cor__shortest_path3.measurement_idD1b
|
0.191
|
NA
|
NA
|
NA
|
-0.062
|
0.647
|
|
|
sub_id
|
cor__shortest_path4.measurement_idD1b
|
-0.024
|
NA
|
NA
|
NA
|
-0.184
|
0.641
|
|
|
Ref. Cat. dist-3
|
|
NA
|
(Intercept)
|
1.416
|
0.211
|
6.714
|
0.000
|
1.003
|
1.829
|
***
|
|
NA
|
shortest_path2
|
0.424
|
0.129
|
3.290
|
0.001
|
0.171
|
0.677
|
**
|
|
NA
|
shortest_path4
|
-0.512
|
0.116
|
-4.427
|
0.000
|
-0.738
|
-0.285
|
***
|
|
NA
|
measurement_idD1b
|
-0.036
|
0.133
|
-0.273
|
0.785
|
-0.296
|
0.224
|
|
|
NA
|
shortest_path2:measurement_idD1b
|
-0.022
|
0.123
|
-0.175
|
0.861
|
-0.263
|
0.220
|
|
|
NA
|
shortest_path4:measurement_idD1b
|
0.223
|
0.129
|
1.722
|
0.085
|
-0.031
|
0.476
|
.
|
|
sub_id
|
sd__(Intercept)
|
1.313
|
NA
|
NA
|
NA
|
1.010
|
1.705
|
|
|
sub_id
|
sd__shortest_path2
|
0.518
|
NA
|
NA
|
NA
|
0.352
|
0.764
|
|
|
sub_id
|
sd__shortest_path4
|
0.338
|
NA
|
NA
|
NA
|
0.190
|
0.603
|
|
|
sub_id
|
sd__measurement_idD1b
|
0.544
|
NA
|
NA
|
NA
|
0.395
|
0.751
|
|
|
sub_id
|
cor__(Intercept).shortest_path2
|
-0.377
|
NA
|
NA
|
NA
|
-0.704
|
0.175
|
|
|
sub_id
|
cor__(Intercept).shortest_path4
|
-0.408
|
NA
|
NA
|
NA
|
-0.681
|
0.342
|
|
|
sub_id
|
cor__(Intercept).measurement_idD1b
|
0.117
|
NA
|
NA
|
NA
|
-0.224
|
0.497
|
|
|
sub_id
|
cor__shortest_path2.shortest_path4
|
-0.046
|
NA
|
NA
|
NA
|
0.106
|
0.502
|
|
|
sub_id
|
cor__shortest_path2.measurement_idD1b
|
-0.191
|
NA
|
NA
|
NA
|
-0.124
|
0.355
|
|
|
sub_id
|
cor__shortest_path4.measurement_idD1b
|
-0.337
|
NA
|
NA
|
NA
|
0.009
|
0.560
|
|
|
Ref. Cat. dist-4
|
|
NA
|
(Intercept)
|
0.904
|
0.193
|
4.684
|
0.000
|
0.526
|
1.283
|
***
|
|
NA
|
shortest_path2
|
0.936
|
0.134
|
6.971
|
0.000
|
0.673
|
1.199
|
***
|
|
NA
|
shortest_path3
|
0.512
|
0.116
|
4.427
|
0.000
|
0.285
|
0.738
|
***
|
|
NA
|
measurement_idD1b
|
0.187
|
0.126
|
1.476
|
0.140
|
-0.061
|
0.434
|
|
|
NA
|
shortest_path2:measurement_idD1b
|
-0.244
|
0.119
|
-2.060
|
0.039
|
-0.477
|
-0.012
|
|
|
NA
|
shortest_path3:measurement_idD1b
|
-0.223
|
0.129
|
-1.722
|
0.085
|
-0.476
|
0.031
|
.
|
|
sub_id
|
sd__(Intercept)
|
1.214
|
NA
|
NA
|
NA
|
0.935
|
1.577
|
|
|
sub_id
|
sd__shortest_path2
|
0.632
|
NA
|
NA
|
NA
|
0.465
|
0.859
|
|
|
sub_id
|
sd__shortest_path3
|
0.338
|
NA
|
NA
|
NA
|
0.190
|
0.603
|
|
|
sub_id
|
sd__measurement_idD1b
|
0.544
|
NA
|
NA
|
NA
|
0.395
|
0.751
|
|
|
sub_id
|
cor__(Intercept).shortest_path2
|
-0.258
|
NA
|
NA
|
NA
|
-0.602
|
0.216
|
|
|
sub_id
|
cor__(Intercept).shortest_path3
|
0.163
|
NA
|
NA
|
NA
|
-0.621
|
0.521
|
|
|
sub_id
|
cor__(Intercept).measurement_idD1b
|
0.033
|
NA
|
NA
|
NA
|
-0.386
|
0.307
|
|
|
sub_id
|
cor__shortest_path2.shortest_path3
|
0.573
|
NA
|
NA
|
NA
|
0.343
|
0.835
|
|
|
sub_id
|
cor__shortest_path2.measurement_idD1b
|
0.024
|
NA
|
NA
|
NA
|
-0.041
|
0.338
|
|
|
sub_id
|
cor__shortest_path3.measurement_idD1b
|
0.337
|
NA
|
NA
|
NA
|
-0.003
|
0.674
|
|
predict_nav_awake <- expand_grid(
measurement_id = c("D1", "D1b"),
shortest_path = factor(2:4),
sub_id = NA, study = NA
) %>%
predict_glmmTMB(stats_nav_awake_dist2)
plot_nav_awake <- nav_study3 %>%
filter(measurement_id %in% c("D1", "D1b")) %>%
group_by(sub_id, measurement_id, shortest_path) %>%
summarise(accuracy = mean(correct), .groups = "drop") %>%
ggplot(aes(x=shortest_path, y=accuracy, color=measurement_id)) +
theme_custom() +
geom_hline(yintercept = 0.5, linetype = "dashed") +
geom_dotplot(
aes(fill = measurement_id),
binwidth = 0.01,
binaxis = "y", stackdir = "center",
position = position_dodge(width = 0.75),
dotsize = 1, alpha = 0.5, color = NA,
show.legend = FALSE
) +
geom_pointrange(
aes(
x = shortest_path, y = fit,
ymin = fit - se.fit, ymax = fit + se.fit,
color = measurement_id
),
data = predict_nav_awake, inherit.aes = FALSE, show.legend = FALSE,
position = position_dodge(width = 0.15), linewidth = 1
) +
geom_line(
aes(
x = shortest_path, y = fit,
group = measurement_id, color = measurement_id
),
data = predict_nav_awake, inherit.aes = FALSE,
position = position_dodge(width = 0.15), linewidth = 1
) +
scale_x_discrete(name = "Shortest path distance") +
scale_y_continuous(
name = "Accuracy", labels = scales::percent, breaks = seq(0, 1, 0.25)
) +
scale_color_manual(
name = "Measurement",
values = c("D1"="#fa9fb5", "D1b"="#2c7fb8"),
labels = c("D1"="Before overnight rest", "D1b"="After awake rest")
) +
scale_fill_manual(values = c("D1"="#fa9fb5", "D1b"="#2c7fb8")) +
coord_cartesian(ylim = c(0.3, 1.1)) +
theme(legend.position = "bottom") +
ggtitle("Navigation after awake rest")
plot_nav_awake

if (knitting) {
ggsave(
here("figures", str_c("navigation_awake_rest", ".pdf")),
plot = plot_nav_awake,
width = 4, height = 3,
units = "in", dpi = 300
)
}
SR replay simulation
Before starting to do any simulation, we first want to know how much
replay an agent can fit into different periods of time. Based on past
research measuring neural replay events, we’ll assume that it takes
about 50ms for the brain to replay a single item from a sequence. This
will let us calculate the total number of items that could be replayed
in each epoch. To simplify the process of actually running the
simulation, we’ll convert this quantity into the number of “sets” that
can be replayed, where a single “set” consists of the total number of
relationships in the network (i.e., the number of undirected edges = 17,
meaning that each set consists of 34 observations because each set
contains observations of both A->B and B->A).
tibble(minutes_for_replay = c(1, 5, 15, 30, 60, 120)) %>%
mutate(
n_items = minutes_for_replay / (0.05 / 60),
n_sets = n_items / 34
) %>%
kbl(
caption = str_c("<center>", "SR replay time", "</center>"),
digits = 2
) %>%
kable_styling(bootstrap_options = c("responsive"))
SR replay time
|
minutes_for_replay
|
n_items
|
n_sets
|
|
1
|
1200
|
35.29
|
|
5
|
6000
|
176.47
|
|
15
|
18000
|
529.41
|
|
30
|
36000
|
1058.82
|
|
60
|
72000
|
2117.65
|
|
120
|
144000
|
4235.29
|
sim_replay_0_min <- simulated_paired_associates %>%
filter(set <= 6) %>%
simulate_sr() %>%
mutate(replay_time = 0)
sim_replay_1_min <- simulated_paired_associates %>%
filter(set <= 35 + 6) %>%
simulate_sr() %>%
mutate(replay_time = 1)
sim_replay_5_min <- simulated_paired_associates %>%
filter(set <= 176 + 6) %>%
simulate_sr() %>%
mutate(replay_time = 5)
sim_replay_60_min <- simulated_paired_associates %>%
filter(set <= 2117 + 6) %>%
simulate_sr() %>%
mutate(replay_time = 60)
plot_sim_sr_replay <- bind_rows(
join_sr(triallist_nav_learned, sim_replay_0_min),
join_sr(triallist_nav_learned, sim_replay_1_min),
join_sr(triallist_nav_learned, sim_replay_5_min),
join_sr(triallist_nav_learned, sim_replay_60_min)
) %>%
# Feed values through softmax
mutate(across(c(opt1_sr, opt2_sr), ~.x * 100)) %>%
expand_grid(temperature = 1) %>%
rowwise() %>%
mutate(
p_correct = softmax(
option_values = c(opt1_sr, opt2_sr),
option_chosen = if_else(correct_choice == opt1_id, 1, 2),
temperature = temperature,
use_inverse_temperature = TRUE
)
) %>%
ungroup() %>%
# For plotting
mutate(
gamma = factor(gamma),
temperature = str_pad(temperature, width = 2, side = "left"),
temperature = str_c(unicode_greek["tau"], " = ", temperature),
replay_time = str_pad(replay_time, width = 2, side = "left"),
replay_time = case_when(
str_detect(replay_time, "1$") ~ str_c(replay_time, " minute of replay"),
replay_time == " 0" ~ "No replay",
TRUE ~ str_c(replay_time, " minutes of replay")
),
replay_time = fct_relevel(replay_time, "No replay")
) %>%
group_by(replay_time, gamma, temperature, shortest_path) %>%
summarise(p_correct = mean(p_correct), .groups = "drop") %>%
# Plot
ggplot(aes(x=shortest_path, y=p_correct, color=gamma)) +
theme_custom() +
facet_grid(cols = vars(replay_time), rows = vars(temperature)) +
geom_hline(yintercept = 0.5, linetype = "dashed") +
geom_line(aes(color = gamma, group = gamma), linewidth = 0.8) +
scale_x_discrete(name = "Shortest path distance") +
scale_y_continuous(name = "Accuracy", labels = scales::percent) +
scale_color_viridis_d(
name = str_c(unicode_greek["gamma"], " = "), option = "turbo", end = 0.9
) +
guides(color = guide_legend(byrow = TRUE, nrow = 1)) +
coord_cartesian(ylim = c(0.5, 1)) +
theme(legend.position = "bottom") +
ggtitle("Simulated effects of SR replay on navigation")
## Joining with `by = join_by(endpoint_id, opt1_id)`
## Warning in left_join(., simulated_sr %>% rename(opt1_sr = sr_value, opt1_id = from, : Detected an unexpected many-to-many relationship between `x` and `y`.
## ℹ Row 1 of `x` matches multiple rows in `y`.
## ℹ Row 45 of `y` matches multiple rows in `x`.
## ℹ If a many-to-many relationship is expected, set `relationship = "many-to-many"` to silence this
## warning.
## Joining with `by = join_by(endpoint_id, opt2_id, gamma, replay_time)`
## Joining with `by = join_by(endpoint_id, opt1_id)`
## Warning in left_join(., simulated_sr %>% rename(opt1_sr = sr_value, opt1_id = from, : Detected an unexpected many-to-many relationship between `x` and `y`.
## ℹ Row 1 of `x` matches multiple rows in `y`.
## ℹ Row 45 of `y` matches multiple rows in `x`.
## ℹ If a many-to-many relationship is expected, set `relationship = "many-to-many"` to silence this
## warning.
## Joining with `by = join_by(endpoint_id, opt2_id, gamma, replay_time)`
## Joining with `by = join_by(endpoint_id, opt1_id)`
## Warning in left_join(., simulated_sr %>% rename(opt1_sr = sr_value, opt1_id = from, : Detected an unexpected many-to-many relationship between `x` and `y`.
## ℹ Row 1 of `x` matches multiple rows in `y`.
## ℹ Row 45 of `y` matches multiple rows in `x`.
## ℹ If a many-to-many relationship is expected, set `relationship = "many-to-many"` to silence this
## warning.
## Joining with `by = join_by(endpoint_id, opt2_id, gamma, replay_time)`
## Joining with `by = join_by(endpoint_id, opt1_id)`
## Warning in left_join(., simulated_sr %>% rename(opt1_sr = sr_value, opt1_id = from, : Detected an unexpected many-to-many relationship between `x` and `y`.
## ℹ Row 1 of `x` matches multiple rows in `y`.
## ℹ Row 45 of `y` matches multiple rows in `x`.
## ℹ If a many-to-many relationship is expected, set `relationship = "many-to-many"` to silence this
## warning.
## Joining with `by = join_by(endpoint_id, opt2_id, gamma, replay_time)`
plot_sim_sr_replay

if (knitting) {
ggsave(
here("figures", str_c("simulated_replay", ".pdf")),
plot = plot_sim_sr_replay,
width = 7, height = 2.5,
units = "in", dpi = 300,
device = cairo_pdf
)
}
PPC before/after rest
plot_ppc_day1_to_day2 <- ppc_sr_behavior %>%
filter(study %in% c("Study 2", "Study 3")) %>%
mutate(
measurement_id = case_when(
measurement_id == "D1" ~ "Before rest",
measurement_id == "D2" ~ "After rest"
),
measurement_id = fct_relevel(measurement_id, "Before rest")
) %>%
pivot_longer(c(empirical, predicted)) %>%
ggplot(aes(x=shortest_path, y=value)) +
theme_custom() +
facet_wrap(~measurement_id) +
geom_hline(yintercept = 0.5, linetype = "dashed") +
geom_point(
aes(color = name),
alpha = 0.05,
position = position_jitterdodge(
jitter.width = 0.2, jitter.height = 0, dodge.width = 0.5, seed = 1
),
show.legend = FALSE
) +
stat_summary(
aes(color = name), geom = "crossbar", fun = mean,
position = position_dodge(0.5)
) +
scale_x_discrete(name = "Shortest path distance") +
scale_y_continuous(
name = "Accuracy", labels = scales::percent, breaks = seq(0, 1, 0.25)
) +
scale_color_manual(
name = NULL,
values = c("empirical"="#fd8d3c", "predicted"="#bd0026"),
labels = c("empirical"="Human", "predicted"="SR")
) +
theme(legend.position = "bottom") +
ggtitle("Posterior predictive check")
plot_ppc_day1_to_day2

if (knitting) {
ggsave(
here("figures", str_c("ppc_day2", ".pdf")),
plot = plot_ppc_day1_to_day2,
width = 8/3, height = 2.5,
units = "in", dpi = 300
)
}
Relating model parameters to navigation
Does estimated gamma significantly increase after overnight rest?
params %>%
filter(
study %in% c("Study 2", "Study 3"),
measurement_id %in% c("D1", "D2"),
model == "sr",
param_name == "sr_gamma"
) %>%
select(study, sub_id, measurement_id, sr_gamma = param_value) %>%
group_by(measurement_id) %>%
summarise(median_gamma = median(sr_gamma)) %>%
kbl(
caption = str_c(
"<center>", "Median SR gamma before/after overnight rest", "</center>"
),
digits = 3
) %>%
kable_styling(bootstrap_options = c("responsive"))
Median SR gamma before/after overnight rest
|
measurement_id
|
median_gamma
|
|
D1
|
0.512
|
|
D2
|
0.659
|
params %>%
filter(
study %in% c("Study 2", "Study 3"),
measurement_id %in% c("D1", "D2"),
model == "sr",
param_name == "sr_gamma"
) %>%
select(study, sub_id, measurement_id, sr_gamma = param_value) %>%
pivot_wider(names_from = measurement_id, values_from = sr_gamma) %>%
with(
wilcox.test(
D2, D1, alternative = "greater", paired = TRUE, conf.int = TRUE
)
) %>%
tidy() %>%
kbl(
caption = str_c(
"<center>", "Increase in SR gamma after overnight rest", "</center>"
),
digits = 3
) %>%
kable_styling(bootstrap_options = c("responsive"))
Increase in SR gamma after overnight rest
|
estimate
|
statistic
|
p.value
|
conf.low
|
conf.high
|
method
|
alternative
|
|
0.064
|
2876
|
0.023
|
0.009
|
Inf
|
Wilcoxon signed rank test with continuity correction
|
greater
|
plot_gamma_change <- params %>%
filter(
study %in% c("Study 2", "Study 3"),
measurement_id %in% c("D1", "D2"),
model == "sr",
param_name == "sr_gamma"
) %>%
select(study, sub_id, measurement_id, sr_gamma = param_value) %>%
ggplot(aes(x=measurement_id, y=sr_gamma, color=measurement_id)) +
theme_custom() +
geom_point(
position = position_jitterdodge(
jitter.width = 0.25, jitter.height = 0, dodge.width = 0.5, seed = 1
),
alpha = 0.25,
show.legend = FALSE
) +
stat_summary(
geom = "crossbar", fun = median, position = "dodge", show.legend = FALSE
) +
scale_x_discrete(
name = "Measurement",
labels = c("D1"="Before rest", "D2"="After rest")
) +
scale_y_continuous(
name = str_c("Estimated ", unicode_greek["gamma"]),
breaks = seq(0, 1, 0.25)
) +
scale_color_manual(
name = "Measurement",
values = c("D1"="#fa9fb5", "D2"="#7a0177"),
labels = c("D1"="Before rest", "D2"="After rest")
) +
coord_cartesian(ylim = c(0, 1.1)) +
theme(legend.position = "bottom") +
ggtitle(
str_c(
unicode_greek["Delta"], unicode_greek["gamma"], " after overnight rest"
)
)
plot_gamma_change

if (knitting) {
ggsave(
here("figures", str_c("gamma_change", ".pdf")),
plot = plot_gamma_change,
width = 8/3, height = 2.5,
units = "in", dpi = 300,
device = cairo_pdf
)
}
Are changes in estimated gamma related to changes in navigation
behaviors?
bind_rows(nav_study2, nav_study3) %>%
filter(measurement_id %in% c("D1", "D2")) %>%
group_by(study, sub_id, measurement_id, shortest_path) %>%
summarise(accuracy = mean(correct), .groups = "drop") %>%
pivot_wider(names_from = measurement_id, values_from = accuracy) %>%
mutate(delta_accuracy = D2 - D1) %>%
select(-c(D1, D2)) %>%
#
left_join(
params %>%
filter(
study %in% c("Study 2", "Study 3"),
measurement_id %in% c("D1", "D2"),
model == "sr",
param_name == "sr_gamma"
) %>%
select(study, sub_id, measurement_id, sr_gamma = param_value) %>%
pivot_wider(names_from = measurement_id, values_from = sr_gamma) %>%
mutate(delta_sr = D2 - D1) %>%
select(-c(D1, D2)),
by = c("study", "sub_id")
) %>%
group_by(shortest_path) %>%
nest() %>%
mutate(
test = map(
.x = data,
.f = ~with(
.x,
cor.test(
delta_accuracy, delta_sr,
method = "spearman", exact = FALSE, alternative = "greater"
)
) %>% tidy()
)
) %>%
unnest(test) %>%
ungroup() %>%
select(-data) %>%
kbl(
caption = str_c(
"<center>", "∆ Accuracy ~ ∆ SR gamma (after overnight rest)", "</center>"
),
digits = 3
) %>%
kable_styling(bootstrap_options = c("responsive"))
∆ Accuracy ~ ∆ SR gamma (after overnight rest)
|
shortest_path
|
estimate
|
statistic
|
p.value
|
method
|
alternative
|
|
2
|
-0.180
|
173977.52
|
0.960
|
Spearman’s rank correlation rho
|
greater
|
|
3
|
0.205
|
117163.09
|
0.022
|
Spearman’s rank correlation rho
|
greater
|
|
4
|
0.453
|
80620.94
|
0.000
|
Spearman’s rank correlation rho
|
greater
|
plot_gamma_accuracy_change <- bind_rows(nav_study2, nav_study3) %>%
filter(measurement_id %in% c("D1", "D2")) %>%
group_by(study, sub_id, measurement_id, shortest_path) %>%
summarise(accuracy = mean(correct), .groups = "drop") %>%
pivot_wider(names_from = measurement_id, values_from = accuracy) %>%
mutate(delta_accuracy = D2 - D1) %>%
select(-c(D1, D2)) %>%
#
left_join(
params %>%
filter(
study %in% c("Study 2", "Study 3"),
measurement_id %in% c("D1", "D2"),
model == "sr",
param_name == "sr_gamma"
) %>%
select(study, sub_id, measurement_id, sr_gamma = param_value) %>%
pivot_wider(names_from = measurement_id, values_from = sr_gamma) %>%
mutate(delta_sr = D2 - D1) %>%
select(-c(D1, D2)),
by = c("study", "sub_id")
) %>%
ggplot(aes(x=delta_sr, y=delta_accuracy, color=shortest_path)) +
theme_custom() +
geom_hline(yintercept = 0, linetype = "dashed") +
geom_vline(xintercept = 0, linetype = "dashed") +
geom_point(alpha = 0.25, show.legend = FALSE) +
geom_smooth(method = "lm", se = FALSE, linewidth = 1.5) +
scale_x_continuous(name = str_c("Change in ", unicode_greek["gamma"])) +
scale_y_continuous(name = "Change in accuracy") +
scale_color_manual(
name = "Shortest path distance",
values = c("#88CCEE", "#CC6677", "#DDCC77")
) +
coord_cartesian(xlim = c(-1, 1.1)) +
theme(legend.position = "bottom") +
ggtitle(
str_c(
unicode_greek["Delta"], "Navigation ~ ",
unicode_greek["Delta"], unicode_greek["gamma"]
)
)
plot_gamma_accuracy_change
## `geom_smooth()` using formula = 'y ~ x'

if (knitting) {
suppressWarnings(
ggsave(
here("figures", str_c("gamma_accuracy_change", ".pdf")),
plot = plot_gamma_accuracy_change,
width = 8/3, height = 2.5,
units = "in", dpi = 300
)
)
ggsave(
here("figures", str_c("gamma_accuracy_change_cairo", ".pdf")),
plot = plot_gamma_accuracy_change,
width = 8/3, height = 2.5,
units = "in", dpi = 300,
device = cairo_pdf
)
}
## `geom_smooth()` using formula = 'y ~ x'
## `geom_smooth()` using formula = 'y ~ x'
Evidence of cached representation
Here, we’re trying to get a sense for what is being cached, and
trying to see if there’s evidence that caching (as opposed to
model-based planning) is the primary driver of navigation improvement
after overnight rest.
Simulation visualization
butterfly_layout <- create_layout(g, layout = "stress")
plot_network_with_sr <- sim_sr_matrix_asymptotic %>%
mutate(
from_sorted = if_else(from < to, from, to),
to_sorted = if_else(from < to, to, from)
) %>%
group_by(gamma, from = from_sorted, to = to_sorted) %>%
summarise(sr_value = mean(sr_value)) %>%
filter(round(gamma, 1) %in% c(0.1, 0.5, 0.9)) %>%
filter(sr_value > 0.05) %>%
left_join(adjlist) %>%
filter(from < to) %>%
mutate(
edge = factor(edge),
gamma = str_c(unicode_greek["gamma"], " = ", gamma)
) %>%
tbl_graph(edges = ., directed = FALSE) %>%
mutate(name = row_number()) %>%
ggraph("manual", x=butterfly_layout$x, y=butterfly_layout$y) +
theme_network() +
facet_edges(~gamma, ncol = 1) +
geom_edge_link(aes(alpha = sr_value, color = edge)) +
geom_node_label(aes(label = name)) +
scale_edge_color_manual(
name = NULL,
values = c("0"="red", "1"="black"),
labels = c("0"="Inferred connections", "1"="Observed connections")
) +
scale_edge_alpha(name = "p(Target | Source)") +
theme(
legend.position = "bottom",
legend.box = "vertical",
strip.background = element_blank(),
strip.text = element_text(size = 13)
) +
ggtitle("Cognitive maps predicted by SR")
## `summarise()` has grouped output by 'gamma', 'from'. You can override using the `.groups` argument.
## Joining with `by = join_by(from, to)`
plot_network_with_sr

if (knitting) {
suppressWarnings(
ggsave(
here("figures", str_c("network_with_sr", ".pdf")),
plot = plot_network_with_sr,
width = 3.5, height = 6,
units = "in", dpi = 300
)
)
ggsave(
here("figures", str_c("network_with_sr_cairo", ".pdf")),
plot = plot_network_with_sr,
width = 3.5, height = 6,
units = "in", dpi = 300,
device = cairo_pdf
)
}
Transition reevaluation
Following transition reevaluation, a caching account predicts that
people’s navigation should get worse relative to their performance after
overnight rest. In contrast, a planning account predicts that people’s
navigation should not be greatly impacted by a relatively small set of
changes.
stats_nav_tr_dist2 <- bind_rows(nav_study2, nav_study3) %>%
filter(measurement_id %in% c("D1", "D2", "D2b")) %>%
mutate(
measurement_id = fct_relevel(measurement_id, "D2b"),
shortest_path = fct_relevel(shortest_path, "2")
) %>%
glmmTMB(
correct ~ shortest_path * measurement_id +
(1 + shortest_path + measurement_id | sub_id) + (1 | study),
family = binomial,
data = .
)
stats_nav_tr_dist3 <- bind_rows(nav_study2, nav_study3) %>%
filter(measurement_id %in% c("D1", "D2", "D2b")) %>%
mutate(
measurement_id = fct_relevel(measurement_id, "D2b"),
shortest_path = fct_relevel(shortest_path, "3")
) %>%
glmmTMB(
correct ~ shortest_path * measurement_id +
(1 + shortest_path + measurement_id | sub_id) + (1 | study),
family = binomial,
data = .
)
stats_nav_tr_dist4 <- bind_rows(nav_study2, nav_study3) %>%
filter(measurement_id %in% c("D1", "D2", "D2b")) %>%
mutate(
measurement_id = fct_relevel(measurement_id, "D2b"),
shortest_path = fct_relevel(shortest_path, "4")
) %>%
glmmTMB(
correct ~ shortest_path * measurement_id +
(1 + shortest_path + measurement_id | sub_id) + (1 | study),
family = binomial,
data = .
)
map_dfr(
.x = list(
"dist-2" = stats_nav_tr_dist2,
"dist-3" = stats_nav_tr_dist3,
"dist-4" = stats_nav_tr_dist4
),
.f = ~tidy(.x, conf.int = TRUE),
.id = "ref_cat"
) %>%
check_significance() %>%
select(-c(ref_cat, effect, component)) %>%
kbl(
caption = str_c(
"<center>", "Navigation accuracy: Transition Reevaluation", "</center>"
),
digits = 3
) %>%
kable_styling(bootstrap_options = c("responsive")) %>%
pack_rows("Ref. Cat. dist-2", 1, 25) %>%
pack_rows("Ref. Cat. dist-3", 26, 50) %>%
pack_rows("Ref. Cat. dist-4", 51, 75)
Navigation accuracy: Transition Reevaluation
|
group
|
term
|
estimate
|
std.error
|
statistic
|
p.value
|
conf.low
|
conf.high
|
sig
|
|
Ref. Cat. dist-2
|
|
NA
|
(Intercept)
|
1.600
|
0.110
|
14.558
|
0.000
|
1.385
|
1.815
|
***
|
|
NA
|
shortest_path3
|
-0.536
|
0.075
|
-7.183
|
0.000
|
-0.682
|
-0.390
|
***
|
|
NA
|
shortest_path4
|
-1.029
|
0.080
|
-12.837
|
0.000
|
-1.187
|
-0.872
|
***
|
|
NA
|
measurement_idD1
|
0.038
|
0.066
|
0.584
|
0.559
|
-0.091
|
0.168
|
|
|
NA
|
measurement_idD2
|
0.181
|
0.068
|
2.657
|
0.008
|
0.048
|
0.315
|
**
|
|
NA
|
shortest_path3:measurement_idD1
|
0.052
|
0.077
|
0.672
|
0.502
|
-0.099
|
0.203
|
|
|
NA
|
shortest_path4:measurement_idD1
|
0.088
|
0.074
|
1.183
|
0.237
|
-0.058
|
0.234
|
|
|
NA
|
shortest_path3:measurement_idD2
|
0.071
|
0.079
|
0.902
|
0.367
|
-0.083
|
0.225
|
|
|
NA
|
shortest_path4:measurement_idD2
|
0.287
|
0.076
|
3.765
|
0.000
|
0.137
|
0.436
|
***
|
|
sub_id
|
sd__(Intercept)
|
0.728
|
NA
|
NA
|
NA
|
0.583
|
0.910
|
|
|
sub_id
|
sd__shortest_path3
|
0.369
|
NA
|
NA
|
NA
|
0.267
|
0.509
|
|
|
sub_id
|
sd__shortest_path4
|
0.437
|
NA
|
NA
|
NA
|
0.339
|
0.564
|
|
|
sub_id
|
sd__measurement_idD1
|
0.275
|
NA
|
NA
|
NA
|
0.193
|
0.391
|
|
|
sub_id
|
sd__measurement_idD2
|
0.285
|
NA
|
NA
|
NA
|
0.200
|
0.407
|
|
|
sub_id
|
cor__(Intercept).shortest_path3
|
0.055
|
NA
|
NA
|
NA
|
-0.307
|
0.397
|
|
|
sub_id
|
cor__(Intercept).shortest_path4
|
-0.353
|
NA
|
NA
|
NA
|
-0.936
|
0.071
|
|
|
sub_id
|
cor__(Intercept).measurement_idD1
|
-0.296
|
NA
|
NA
|
NA
|
-0.440
|
0.119
|
|
|
sub_id
|
cor__(Intercept).measurement_idD2
|
0.414
|
NA
|
NA
|
NA
|
-0.036
|
0.488
|
|
|
sub_id
|
cor__shortest_path3.shortest_path4
|
0.865
|
NA
|
NA
|
NA
|
0.194
|
0.932
|
|
|
sub_id
|
cor__shortest_path3.measurement_idD1
|
-0.181
|
NA
|
NA
|
NA
|
-0.216
|
0.273
|
|
|
sub_id
|
cor__shortest_path3.measurement_idD2
|
0.171
|
NA
|
NA
|
NA
|
-0.246
|
0.510
|
|
|
sub_id
|
cor__shortest_path4.measurement_idD1
|
-0.103
|
NA
|
NA
|
NA
|
0.245
|
0.333
|
|
|
sub_id
|
cor__shortest_path4.measurement_idD2
|
-0.044
|
NA
|
NA
|
NA
|
-0.188
|
0.433
|
|
|
sub_id
|
cor__measurement_idD1.measurement_idD2
|
0.356
|
NA
|
NA
|
NA
|
0.560
|
0.808
|
|
|
study
|
sd__(Intercept)
|
0.028
|
NA
|
NA
|
NA
|
0.004
|
0.181
|
|
|
Ref. Cat. dist-3
|
|
NA
|
(Intercept)
|
1.064
|
0.124
|
8.567
|
0.000
|
0.821
|
1.307
|
***
|
|
NA
|
shortest_path2
|
0.536
|
0.075
|
7.183
|
0.000
|
0.390
|
0.682
|
***
|
|
NA
|
shortest_path4
|
-0.493
|
0.061
|
-8.036
|
0.000
|
-0.614
|
-0.373
|
***
|
|
NA
|
measurement_idD1
|
0.090
|
0.071
|
1.277
|
0.201
|
-0.048
|
0.229
|
|
|
NA
|
measurement_idD2
|
0.252
|
0.073
|
3.446
|
0.001
|
0.109
|
0.396
|
***
|
|
NA
|
shortest_path2:measurement_idD1
|
-0.052
|
0.077
|
-0.672
|
0.501
|
-0.203
|
0.099
|
|
|
NA
|
shortest_path4:measurement_idD1
|
0.036
|
0.078
|
0.459
|
0.646
|
-0.118
|
0.190
|
|
|
NA
|
shortest_path2:measurement_idD2
|
-0.071
|
0.079
|
-0.902
|
0.367
|
-0.225
|
0.083
|
|
|
NA
|
shortest_path4:measurement_idD2
|
0.216
|
0.080
|
2.684
|
0.007
|
0.058
|
0.374
|
**
|
|
sub_id
|
sd__(Intercept)
|
0.834
|
NA
|
NA
|
NA
|
0.664
|
1.048
|
|
|
sub_id
|
sd__shortest_path2
|
0.369
|
NA
|
NA
|
NA
|
0.267
|
0.509
|
|
|
sub_id
|
sd__shortest_path4
|
0.220
|
NA
|
NA
|
NA
|
0.137
|
0.353
|
|
|
sub_id
|
sd__measurement_idD1
|
0.275
|
NA
|
NA
|
NA
|
0.193
|
0.391
|
|
|
sub_id
|
sd__measurement_idD2
|
0.285
|
NA
|
NA
|
NA
|
0.200
|
0.407
|
|
|
sub_id
|
cor__(Intercept).shortest_path2
|
-0.490
|
NA
|
NA
|
NA
|
-0.717
|
-0.095
|
|
|
sub_id
|
cor__(Intercept).shortest_path4
|
-0.675
|
NA
|
NA
|
NA
|
-0.753
|
0.183
|
|
|
sub_id
|
cor__(Intercept).measurement_idD1
|
-0.338
|
NA
|
NA
|
NA
|
-0.491
|
0.099
|
|
|
sub_id
|
cor__(Intercept).measurement_idD2
|
0.437
|
NA
|
NA
|
NA
|
-0.051
|
0.528
|
|
|
sub_id
|
cor__shortest_path2.shortest_path4
|
-0.042
|
NA
|
NA
|
NA
|
0.134
|
0.401
|
|
|
sub_id
|
cor__shortest_path2.measurement_idD1
|
0.181
|
NA
|
NA
|
NA
|
0.180
|
0.357
|
|
|
sub_id
|
cor__shortest_path2.measurement_idD2
|
-0.172
|
NA
|
NA
|
NA
|
-0.180
|
0.211
|
|
|
sub_id
|
cor__shortest_path4.measurement_idD1
|
0.099
|
NA
|
NA
|
NA
|
0.324
|
0.614
|
|
|
sub_id
|
cor__shortest_path4.measurement_idD2
|
-0.376
|
NA
|
NA
|
NA
|
-0.005
|
0.537
|
|
|
sub_id
|
cor__measurement_idD1.measurement_idD2
|
0.356
|
NA
|
NA
|
NA
|
0.549
|
0.793
|
|
|
study
|
sd__(Intercept)
|
0.028
|
NA
|
NA
|
NA
|
0.004
|
0.181
|
|
|
Ref. Cat. dist-4
|
|
NA
|
(Intercept)
|
0.571
|
0.106
|
5.360
|
0.000
|
0.362
|
0.779
|
***
|
|
NA
|
shortest_path2
|
1.029
|
0.080
|
12.836
|
0.000
|
0.872
|
1.187
|
***
|
|
NA
|
shortest_path3
|
0.493
|
0.061
|
8.036
|
0.000
|
0.373
|
0.614
|
***
|
|
NA
|
measurement_idD1
|
0.126
|
0.067
|
1.898
|
0.058
|
-0.004
|
0.257
|
.
|
|
NA
|
measurement_idD2
|
0.468
|
0.070
|
6.722
|
0.000
|
0.332
|
0.605
|
***
|
|
NA
|
shortest_path2:measurement_idD1
|
-0.088
|
0.074
|
-1.183
|
0.237
|
-0.234
|
0.058
|
|
|
NA
|
shortest_path3:measurement_idD1
|
-0.036
|
0.078
|
-0.459
|
0.646
|
-0.190
|
0.118
|
|
|
NA
|
shortest_path2:measurement_idD2
|
-0.287
|
0.076
|
-3.765
|
0.000
|
-0.436
|
-0.137
|
***
|
|
NA
|
shortest_path3:measurement_idD2
|
-0.216
|
0.080
|
-2.684
|
0.007
|
-0.374
|
-0.058
|
**
|
|
sub_id
|
sd__(Intercept)
|
0.705
|
NA
|
NA
|
NA
|
0.559
|
0.889
|
|
|
sub_id
|
sd__shortest_path2
|
0.437
|
NA
|
NA
|
NA
|
0.339
|
0.564
|
|
|
sub_id
|
sd__shortest_path3
|
0.220
|
NA
|
NA
|
NA
|
0.137
|
0.353
|
|
|
sub_id
|
sd__measurement_idD1
|
0.275
|
NA
|
NA
|
NA
|
0.193
|
0.391
|
|
|
sub_id
|
sd__measurement_idD2
|
0.285
|
NA
|
NA
|
NA
|
0.200
|
0.407
|
|
|
sub_id
|
cor__(Intercept).shortest_path2
|
-0.256
|
NA
|
NA
|
NA
|
-0.545
|
0.121
|
|
|
sub_id
|
cor__(Intercept).shortest_path3
|
0.487
|
NA
|
NA
|
NA
|
-0.449
|
0.629
|
|
|
sub_id
|
cor__(Intercept).measurement_idD1
|
-0.370
|
NA
|
NA
|
NA
|
-0.578
|
0.074
|
|
|
sub_id
|
cor__(Intercept).measurement_idD2
|
0.400
|
NA
|
NA
|
NA
|
-0.098
|
0.476
|
|
|
sub_id
|
cor__shortest_path2.shortest_path3
|
0.538
|
NA
|
NA
|
NA
|
0.141
|
0.799
|
|
|
sub_id
|
cor__shortest_path2.measurement_idD1
|
0.103
|
NA
|
NA
|
NA
|
0.104
|
0.288
|
|
|
sub_id
|
cor__shortest_path2.measurement_idD2
|
0.044
|
NA
|
NA
|
NA
|
-0.147
|
0.342
|
|
|
sub_id
|
cor__shortest_path3.measurement_idD1
|
-0.099
|
NA
|
NA
|
NA
|
-0.110
|
0.437
|
|
|
sub_id
|
cor__shortest_path3.measurement_idD2
|
0.376
|
NA
|
NA
|
NA
|
-0.487
|
0.641
|
|
|
sub_id
|
cor__measurement_idD1.measurement_idD2
|
0.356
|
NA
|
NA
|
NA
|
0.407
|
0.819
|
|
|
study
|
sd__(Intercept)
|
0.028
|
NA
|
NA
|
NA
|
0.004
|
0.181
|
|
predict_tr <- expand_grid(
measurement_id = c("D1", "D2", "D2b"),
shortest_path = factor(2:4),
sub_id = NA, study = NA
) %>%
predict_glmmTMB(stats_nav_tr_dist2)
plot_nav_tr <- nav_study3 %>%
filter(measurement_id %in% c("D1", "D2", "D2b")) %>%
group_by(sub_id, measurement_id, shortest_path) %>%
summarise(accuracy = mean(correct), .groups = "drop") %>%
ggplot(aes(x=shortest_path, y=accuracy, color=measurement_id)) +
theme_custom() +
geom_hline(yintercept = 0.5, linetype = "dashed") +
geom_dotplot(
aes(fill = measurement_id),
binwidth = 0.01,
binaxis = "y", stackdir = "center",
position = position_dodge(width = 0.75),
dotsize = 1, alpha = 0.5, color = NA,
show.legend = FALSE
) +
geom_pointrange(
aes(
x = shortest_path, y = fit,
ymin = fit - se.fit, ymax = fit + se.fit,
color = measurement_id
),
data = predict_tr, inherit.aes = FALSE, show.legend = FALSE,
position = position_dodge(width = 0.25), linewidth = 1
) +
geom_line(
aes(
x = shortest_path, y = fit,
group = measurement_id, color = measurement_id
),
data = predict_tr, inherit.aes = FALSE,
position = position_dodge(width = 0.25), linewidth = 1
) +
scale_x_discrete(name = "Shortest path distance") +
scale_y_continuous(
name = "Accuracy", labels = scales::percent, breaks = seq(0, 1, 0.25)
) +
scale_color_manual(
name = "Measurement",
values = c("D1"="#fa9fb5", "D2"="#7a0177", "D2b"="#238b45"),
labels = c(
"D1"="Before overnight rest",
"D2"="After overnight rest",
"D2b"="After reevaluation"
)
) +
scale_fill_manual(
values = c("D1"="#fa9fb5", "D2"="#7a0177", "D2b"="#238b45")
) +
coord_cartesian(ylim = c(0.3, 1.1)) +
theme(legend.position = "bottom") +
ggtitle("Navigation after transition reevaluation")
plot_nav_tr

if (knitting) {
ggsave(
here("figures", str_c("navigation_reevaluation", ".pdf")),
plot = plot_nav_tr,
width = 4, height = 4,
units = "in", dpi = 300
)
}
LS0tCnRpdGxlOiAiQW5hbHlzZXMgZm9yIG1haW4gdGV4dCIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IHRydWUKLS0tCgojIFNldHVwCgpgYGB7ciBsaWJyYXJpZXN9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGhlcmUpCgpsaWJyYXJ5KGdsbW1UTUIpCmxpYnJhcnkoYnJvb20ubWl4ZWQpCgpsaWJyYXJ5KHRpZHlncmFwaCkKbGlicmFyeShnZ3JhcGgpCgpsaWJyYXJ5KGthYmxlRXh0cmEpCmxpYnJhcnkodGljdG9jKQpgYGAKCmBgYHtyIGN1c3RvbS1mdW5jdGlvbnN9CnNvdXJjZShoZXJlKCJjb2RlIiwgInV0aWxzIiwgImdncGxvdF90aGVtZXMuUiIpKQpzb3VyY2UoaGVyZSgiY29kZSIsICJ1dGlscyIsICJtb2RlbGluZ191dGlscy5SIikpCnNvdXJjZShoZXJlKCJjb2RlIiwgInV0aWxzIiwgInJlcHJlc2VudGF0aW9uX3V0aWxzLlIiKSkKc291cmNlKGhlcmUoImNvZGUiLCAidXRpbHMiLCAidW5pY29kZV9ncmVlay5SIikpCgpwcmVkaWN0X2dsbW1UTUIgPC0gZnVuY3Rpb24obWFrZV9wcmVkaWN0aW9uc19mb3IsIG1vZGVsX29iamVjdCkgewogIG1ha2VfcHJlZGljdGlvbnNfZm9yICU+JQogICAgYmluZF9jb2xzKAogICAgICBwcmVkaWN0KAogICAgICAgIG9iamVjdCA9IG1vZGVsX29iamVjdCwKICAgICAgICBuZXdkYXRhID0gLiwKICAgICAgICByZS5mb3JtID0gTkEsIGFsbG93Lm5ldy5sZXZlbHMgPSBUUlVFLCBzZS5maXQgPSBUUlVFLCB0eXBlID0gInJlc3BvbnNlIgogICAgICApCiAgICApCn0KCmNoZWNrX3NpZ25pZmljYW5jZSA8LSBmdW5jdGlvbih0aWR5X2RmKSB7CiAgdGlkeV9kZiAlPiUKICAgIG11dGF0ZSgKICAgICAgc2lnID0gY2FzZV93aGVuKAogICAgICAgIHAudmFsdWUgPCAwLjAwMSB+ICIqKioiLAogICAgICAgIHAudmFsdWUgPCAwLjAxIH4gIioqIiwKICAgICAgICBwLnZhbHVlIDwgMC4wNSB+ICIqIiwKICAgICAgICBwLnZhbHVlIDwgMC4xIH4gIi4iLAogICAgICAgIFRSVUUgfiAiIgogICAgICApCiAgICApCn0KYGBgCgpgYGB7ciBrbml0dGluZy1zZXR1cH0KIyBUbyBjb250cm9sIHdoZW4gdG8gc2F2ZSBmaWd1cmVzCmtuaXR0aW5nIDwtIGtuaXRyOjppc19odG1sX291dHB1dCgpCgppZiAoa25pdHRpbmcpIHsKICBpZiAoIWRpci5leGlzdHMoaGVyZSgiZmlndXJlcyIpKSkgewogICAgZGlyLmNyZWF0ZShoZXJlKCJmaWd1cmVzIikpCiAgfQp9CmBgYAoKCiMgTmV0d29yayB2aXN1YWxpemF0aW9ucwoKYGBge3IgbG9hZC1uZXR3b3JrLWRhdGF9CmFkamxpc3QgPC0gaGVyZSgiZGF0YSIsICJjbGVhbi1kYXRhIiwgImFkamxpc3RfbGVhcm5lZC5jc3YiKSAlPiUKICByZWFkX2NzdihzaG93X2NvbF90eXBlcyA9IEZBTFNFKQoKZyA8LSBhZGpsaXN0ICU+JQogIGZpbHRlcihmcm9tIDwgdG8sIGVkZ2UgPT0gMSkgJT4lCiAgc2VsZWN0KC1lZGdlKSAlPiUKICB0YmxfZ3JhcGgoZWRnZXMgPSAuLCBkaXJlY3RlZCA9IEZBTFNFKQoKYWRqbGlzdF9yZWV2YWx1YXRlZCA8LSBoZXJlKCJkYXRhIiwgImNsZWFuLWRhdGEiLCAiYWRqbGlzdF9yZWV2YWx1YXRlZC5jc3YiKSAlPiUKICByZWFkX2NzdihzaG93X2NvbF90eXBlcyA9IEZBTFNFKQoKZ19yZWV2YWx1YXRlZCA8LSBhZGpsaXN0X3JlZXZhbHVhdGVkICU+JQogIGZpbHRlcihmcm9tIDwgdG8sIGVkZ2UgPT0gMSkgJT4lCiAgc2VsZWN0KC1lZGdlKSAlPiUKICB0YmxfZ3JhcGgoZWRnZXMgPSAuLCBkaXJlY3RlZCA9IEZBTFNFKQpgYGAKCmBgYHtyIHBsb3QtbmV0d29ya3N9CnBsb3RfbmV0d29ya19sZWFybmVkIDwtIGcgJT4lCiAgbXV0YXRlKG5hbWUgPSByb3dfbnVtYmVyKCkpICU+JQogIGdncmFwaCgic3RyZXNzIikgKwogIHRoZW1lX25ldHdvcmsoKSArCiAgZ2VvbV9lZGdlX2xpbmsoKSArCiAgZ2VvbV9ub2RlX2xhYmVsKGFlcyhsYWJlbCA9IG5hbWUpKQoKcGxvdF9uZXR3b3JrX3JlZXZhbHVhdGVkIDwtIGdfcmVldmFsdWF0ZWQgJT4lCiAgbXV0YXRlKG5hbWUgPSByb3dfbnVtYmVyKCkpICU+JQogIGdncmFwaCgic3RyZXNzIikgKwogIHRoZW1lX25ldHdvcmsoKSArCiAgZ2VvbV9lZGdlX2xpbmsoKSArCiAgZ2VvbV9ub2RlX2xhYmVsKGFlcyhsYWJlbCA9IG5hbWUpKQoKcGxvdF9uZXR3b3JrX2xlYXJuZWQKcGxvdF9uZXR3b3JrX3JlZXZhbHVhdGVkCgppZiAoa25pdHRpbmcpIHsKICBnZ3NhdmUoCiAgICBoZXJlKCJmaWd1cmVzIiwgc3RyX2MoIm5ldHdvcmtfbGVhcm5lZCIsICIucGRmIikpLAogICAgcGxvdCA9IHBsb3RfbmV0d29ya19sZWFybmVkLAogICAgd2lkdGggPSA0LCBoZWlnaHQgPSAyLAogICAgdW5pdHMgPSAiaW4iLCBkcGkgPSAzMDAKICApCiAgCiAgZ2dzYXZlKAogICAgaGVyZSgiZmlndXJlcyIsIHN0cl9jKCJuZXR3b3JrX3JlZXZhbHVhdGVkIiwgIi5wZGYiKSksCiAgICBwbG90ID0gcGxvdF9uZXR3b3JrX3JlZXZhbHVhdGVkLAogICAgd2lkdGggPSA0LCBoZWlnaHQgPSAyLAogICAgdW5pdHMgPSAiaW4iLCBkcGkgPSAzMDAKICApCn0KYGBgCgoKIyBDYW4gaHVtYW5zIHNvbHZlIHNvY2lhbCBuYXZpZ2F0aW9uIHByb2JsZW1zPwoKSW4gdGhlIHBhcGVyLCB3ZSBzdGFydCBieSBleGFtaW5pbmcgc29jaWFsIG5hdmlnYXRpb24gYmVoYXZpb3JzIGluIGEgb25lLWRheSBzZXNzaW9uIChTdHVkeSAxKSwgb3IgaW4gdGhlIGZpcnN0IHNlc3Npb24gb2YgYSB0d28tZGF5IHN0dWR5IChTdHVkaWVzIDItMykuIEFjcm9zcyBhbGwgdGhyZWUgc3R1ZGllcywgdGhlIHByb2NlZHVyZSBpcyBleGFjdGx5IGlkZW50aWNhbDsgc3R1ZGllcyAyLTMgYXJlLCBpbiB0aGlzIHBhcnQgb2YgdGhlIGRhdGFzZXQsIGV4YWN0IHJlcGxpY2F0aW9ucyBvZiBzdHVkeSAxLgoKYGBge3IgbG9hZC1uYXZpZ2F0aW9uLWRhdGF9Cm5hdl9zdHVkeTEgPC0gaGVyZSgiZGF0YSIsICJjbGVhbi1kYXRhIiwgInN0dWR5MV9tZXNzYWdlX3Bhc3NpbmcuY3N2IikgJT4lCiAgcmVhZF9jc3Yoc2hvd19jb2xfdHlwZXMgPSBGQUxTRSkgJT4lCiAgZmlsdGVyKAogICAgdHdvX2NvcnJlY3Rfb3B0aW9ucyA9PSBGQUxTRSwKICAgIHNob3J0ZXN0X3BhdGhfZ2l2ZW5fb3B0cyA9PSBzaG9ydGVzdF9wYXRoX2dpdmVuX3N0YXJ0X2VuZAogICkgJT4lCiAgbXV0YXRlKAogICAgc3R1ZHkgPSAiU3R1ZHkgMSIsCiAgICBtZWFzdXJlbWVudF9pZCA9IHN0cl9jKCJEIiwgbWVhc3VyZW1lbnRfaWQpLAogICAgc2hvcnRlc3RfcGF0aCA9IGZhY3RvcihzaG9ydGVzdF9wYXRoX2dpdmVuX29wdHMpCiAgKSAlPiUKICBzZWxlY3QoCiAgICBzdHVkeSwgc3ViX2lkLCBtZWFzdXJlbWVudF9pZCwgc2hvcnRlc3RfcGF0aCwKICAgIHN0YXJ0cG9pbnRfaWQsIGVuZHBvaW50X2lkLAogICAgb3B0MV9pZCwgb3B0Ml9pZCwKICAgIGNvcnJlY3RfY2hvaWNlLCBzdWJfY2hvaWNlLAogICAgY29ycmVjdCwgcnQKICApCgpuYXZfc3R1ZHkyIDwtIGhlcmUoImRhdGEiLCAiY2xlYW4tZGF0YSIsICJzdHVkeTJfbWVzc2FnZV9wYXNzaW5nLmNzdiIpICU+JQogIHJlYWRfY3N2KHNob3dfY29sX3R5cGVzID0gRkFMU0UpICU+JQogIGZpbHRlcigKICAgIHR3b19jb3JyZWN0X29wdGlvbnMgPT0gRkFMU0UsCiAgICBzaG9ydGVzdF9wYXRoX2dpdmVuX29wdHMgPT0gc2hvcnRlc3RfcGF0aF9naXZlbl9zdGFydF9lbmQKICApICU+JQogIG11dGF0ZSgKICAgIHN0dWR5ID0gIlN0dWR5IDIiLAogICAgbWVhc3VyZW1lbnRfaWQgPSBjYXNlX3doZW4oCiAgICAgIG5ldHdvcmsgPT0gImxlYXJuZWQiIH4gc3RyX2MoIkQiLCBtZWFzdXJlbWVudF9pZCksCiAgICAgIG5ldHdvcmsgPT0gInJlZXZhbHVhdGVkIiB+ICJEMmIiCiAgICApLAogICAgc2hvcnRlc3RfcGF0aCA9IGZhY3RvcihzaG9ydGVzdF9wYXRoX2dpdmVuX29wdHMpCiAgKSAlPiUKICBzZWxlY3QoCiAgICBzdHVkeSwgc3ViX2lkLCBtZWFzdXJlbWVudF9pZCwgc2hvcnRlc3RfcGF0aCwKICAgIHN0YXJ0cG9pbnRfaWQsIGVuZHBvaW50X2lkLAogICAgb3B0MV9pZCwgb3B0Ml9pZCwKICAgIGNvcnJlY3RfY2hvaWNlLCBzdWJfY2hvaWNlLAogICAgY29ycmVjdCwgcnQKICApCgpuYXZfc3R1ZHkzIDwtIGhlcmUoImRhdGEiLCAiY2xlYW4tZGF0YSIsICJzdHVkeTNfbWVzc2FnZV9wYXNzaW5nLmNzdiIpICU+JQogIHJlYWRfY3N2KHNob3dfY29sX3R5cGVzID0gRkFMU0UpICU+JQogIGZpbHRlcigKICAgIHR3b19jb3JyZWN0X29wdGlvbnMgPT0gRkFMU0UsCiAgICBzaG9ydGVzdF9wYXRoX2dpdmVuX29wdHMgPT0gc2hvcnRlc3RfcGF0aF9naXZlbl9zdGFydF9lbmQKICApICU+JQogIG11dGF0ZSgKICAgIHN0dWR5ID0gIlN0dWR5IDMiLAogICAgbWVhc3VyZW1lbnRfaWQgPSBjYXNlX3doZW4oCiAgICAgIG5ldHdvcmsgPT0gInJlZXZhbHVhdGVkIiB+ICJEMmIiLAogICAgICBtZWFzdXJlbWVudF9pZCA9PSAxIH4gIkQxIiwKICAgICAgbWVhc3VyZW1lbnRfaWQgPT0gMiB+ICJEMWIiLAogICAgICBtZWFzdXJlbWVudF9pZCA9PSAzIH4gIkQyIgogICAgKSwKICAgIHNob3J0ZXN0X3BhdGggPSBmYWN0b3Ioc2hvcnRlc3RfcGF0aF9naXZlbl9vcHRzKQogICkgJT4lCiAgc2VsZWN0KAogICAgc3R1ZHksIHN1Yl9pZCwgbWVhc3VyZW1lbnRfaWQsIHNob3J0ZXN0X3BhdGgsCiAgICBzdGFydHBvaW50X2lkLCBlbmRwb2ludF9pZCwKICAgIG9wdDFfaWQsIG9wdDJfaWQsCiAgICBjb3JyZWN0X2Nob2ljZSwgc3ViX2Nob2ljZSwKICAgIGNvcnJlY3QsIHJ0CiAgKQpgYGAKCldlJ2xsIHN0YXJ0IG9mZiB3aXRoIHNvbWUgZGVzY3JpcHRpdmUgc3RhdGlzdGljcyBvZiBodW1hbiBiZWhhdmlvci4gVG8gbWF4aW1pemUgc3RhdGlzdGljYWwgcG93ZXIsIHdlIHdpbGwgcG9vbCBhY3Jvc3Mgc3R1ZGllcyB3aGVuZXZlciBwb3NzaWJsZS4KCmBgYHtyIGRlc2NyaXB0aXZlLW5hdmlnYXRpb24tZGF5MX0KYmluZF9yb3dzKG5hdl9zdHVkeTEsIG5hdl9zdHVkeTIsIG5hdl9zdHVkeTMpICU+JQogIGZpbHRlcihtZWFzdXJlbWVudF9pZCA9PSAiRDEiKSAlPiUKICBncm91cF9ieShtZWFzdXJlbWVudF9pZCwgc2hvcnRlc3RfcGF0aCkgJT4lCiAgc3VtbWFyaXNlKGFjY3VyYWN5ID0gbWVhbihjb3JyZWN0KSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lCiAgYXJyYW5nZShtZWFzdXJlbWVudF9pZCwgc2hvcnRlc3RfcGF0aCkgJT4lCiAgcGl2b3Rfd2lkZXIoCiAgICBuYW1lc19mcm9tID0gc2hvcnRlc3RfcGF0aCwgdmFsdWVzX2Zyb20gPSBhY2N1cmFjeSwgbmFtZXNfcHJlZml4ID0gImRpc3QtIgogICkgJT4lCiAga2JsKAogICAgY2FwdGlvbiA9IHN0cl9jKAogICAgICAiPGNlbnRlcj4iLCAiRGVzY3JpcHRpdmU6IE5hdmlnYXRpb24gYWNjdXJhY3kiLCAiPC9jZW50ZXI+IgogICAgKSwKICAgIGRpZ2l0cyA9IDIKICApICU+JQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJyZXNwb25zaXZlIikpCmBgYAoKQW5kIG5vdyB0aGUgaW5mZXJlbnRpYWwgc3RhdGlzdGljYWwgdGVzdHMuIE5vdGUgdGhhdCB3ZSdyZSBpbnRlcmVzdGVkIGluIGtub3dpbmcgd2hldGhlciBuYXZpZ2F0aW9uIGFjY3VyYWN5IGRpZmZlcnMgZnJvbSBjaGFuY2UgYXQgZWFjaCBkaXN0YW5jZSwgc28gd2UnbGwgZXN0aW1hdGUgdGhlIHNhbWUgc3RhdGlzdGljYWwgbW9kZWwgbXVsdGlwbGUgdGltZXMsIGNoYW5naW5nIHRoZSByZWZlcmVuY2UgY2F0ZWdvcnkgZWFjaCB0aW1lLiBOb3RlIHRoYXQgdGhpcyBvbmx5IHJlcGFyYW1ldGVyaXplcyB0aGUgbW9kZWwsIHN1Y2ggdGhhdCB0aGUgKnNhbWUqIHZhcmlhbmNlIGlzIGFjY291bnRlZCBmb3IgYnkgZGlmZmVyZW50IHBhcmFtZXRlcnM7IGl0IGRvZXMgKm5vdCogY2hhbmdlIHRoZSB0b3RhbCBhbW91bnQgb2YgdmFyaWFuY2UgYWNjb3VudGVkIGZvci4KCmBgYHtyIHN0YXRzLWRheTF9Cm5hdl9kYXkxIDwtIGJpbmRfcm93cyhuYXZfc3R1ZHkxLCBuYXZfc3R1ZHkyLCBuYXZfc3R1ZHkzKSAlPiUKICBmaWx0ZXIobWVhc3VyZW1lbnRfaWQgPT0gIkQxIikgJT4lCiAgIyBHaXZlIGV2ZXJ5IHN1YmplY3QgYSBkaXN0aW5jdCBpZGVudGlmaWVyCiAgbXV0YXRlKHN1Yl9pZCA9IHN0cl9jKHN0dWR5LCAiIHMiLCBzdWJfaWQpKQoKc3RhdHNfbmF2X2RheTFfZGlzdDIgPC0gbmF2X2RheTEgJT4lCiAgbXV0YXRlKHNob3J0ZXN0X3BhdGggPSBmY3RfcmVsZXZlbChzaG9ydGVzdF9wYXRoLCAiMiIpKSAlPiUKICBnbG1tVE1CKAogICAgY29ycmVjdCB+IHNob3J0ZXN0X3BhdGggKyAoMSArIHNob3J0ZXN0X3BhdGggfCBzdWJfaWQpICsgKDEgfCBzdHVkeSksCiAgICBmYW1pbHkgPSBiaW5vbWlhbCwKICAgIGRhdGEgPSAuCiAgKQoKc3RhdHNfbmF2X2RheTFfZGlzdDMgPC0gbmF2X2RheTEgJT4lCiAgbXV0YXRlKHNob3J0ZXN0X3BhdGggPSBmY3RfcmVsZXZlbChzaG9ydGVzdF9wYXRoLCAiMyIpKSAlPiUKICBnbG1tVE1CKAogICAgY29ycmVjdCB+IHNob3J0ZXN0X3BhdGggKyAoMSArIHNob3J0ZXN0X3BhdGggfCBzdWJfaWQpICsgKDEgfCBzdHVkeSksCiAgICBmYW1pbHkgPSBiaW5vbWlhbCwKICAgIGRhdGEgPSAuCiAgKQoKc3RhdHNfbmF2X2RheTFfZGlzdDQgPC0gbmF2X2RheTEgJT4lCiAgbXV0YXRlKHNob3J0ZXN0X3BhdGggPSBmY3RfcmVsZXZlbChzaG9ydGVzdF9wYXRoLCAiNCIpKSAlPiUKICBnbG1tVE1CKAogICAgY29ycmVjdCB+IHNob3J0ZXN0X3BhdGggKyAoMSArIHNob3J0ZXN0X3BhdGggfCBzdWJfaWQpICsgKDEgfCBzdHVkeSksCiAgICBmYW1pbHkgPSBiaW5vbWlhbCwKICAgIGRhdGEgPSAuCiAgKQoKbWFwX2RmcigKICAueCA9IGxpc3QoCiAgICAiZGlzdC0yIiA9IHN0YXRzX25hdl9kYXkxX2Rpc3QyLAogICAgImRpc3QtMyIgPSBzdGF0c19uYXZfZGF5MV9kaXN0MywKICAgICJkaXN0LTQiID0gc3RhdHNfbmF2X2RheTFfZGlzdDQKICApLAogIC5mID0gfnRpZHkoLngsIGNvbmYuaW50ID0gVFJVRSksCiAgLmlkID0gInJlZl9jYXQiCikgJT4lCiAgY2hlY2tfc2lnbmlmaWNhbmNlKCkgJT4lCiAgc2VsZWN0KC1jKHJlZl9jYXQsIGVmZmVjdCwgY29tcG9uZW50KSkgJT4lCiAga2JsKAogICAgY2FwdGlvbiA9IHN0cl9jKCI8Y2VudGVyPiIsICJOYXZpZ2F0aW9uIGFjY3VyYWN5OiBEYXkgMSIsICI8L2NlbnRlcj4iKSwKICAgIGRpZ2l0cyA9IDMKICApICU+JQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJyZXNwb25zaXZlIikpICU+JQogIHBhY2tfcm93cygiUmVmLiBDYXQuIGRpc3QtMiIsIDEsIDEwKSAlPiUKICBwYWNrX3Jvd3MoIlJlZi4gQ2F0LiBkaXN0LTMiLCAxMSwgMjApICU+JQogIHBhY2tfcm93cygiUmVmLiBDYXQuIGRpc3QtNCIsIDIxLCAzMCkKYGBgCgpXZSdsbCBwbG90IG91dCB0aGUgcmF3IGRhdGEsIHBsdXMgbW9kZWwgcHJlZGljdGlvbnMuLi4KCmBgYHtyIHBsb3QtZGF5MX0KcHJlZGljdF9uYXZfZGF5MSA8LSBleHBhbmRfZ3JpZCgKICBtZWFzdXJlbWVudF9pZCA9ICJEMSIsCiAgc2hvcnRlc3RfcGF0aCA9IGZhY3RvcigyOjQpLAogIHN1Yl9pZCA9IE5BLCBzdHVkeSA9IE5BCikgJT4lCiAgcHJlZGljdF9nbG1tVE1CKHN0YXRzX25hdl9kYXkxX2Rpc3QyKQoKcGxvdF9uYXZfZGF5MSA8LSBiaW5kX3Jvd3MobmF2X3N0dWR5MiwgbmF2X3N0dWR5MykgJT4lCiAgZmlsdGVyKG1lYXN1cmVtZW50X2lkID09ICJEMSIpICU+JQogIGdyb3VwX2J5KHN1Yl9pZCwgbWVhc3VyZW1lbnRfaWQsIHNob3J0ZXN0X3BhdGgpICU+JQogIHN1bW1hcmlzZShhY2N1cmFjeSA9IG1lYW4oY29ycmVjdCksIC5ncm91cHMgPSAiZHJvcCIpICU+JQogIGdncGxvdChhZXMoeD1zaG9ydGVzdF9wYXRoLCB5PWFjY3VyYWN5KSkgKwogIHRoZW1lX2N1c3RvbSgpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLjUsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX2RvdHBsb3QoCiAgICBiaW53aWR0aCA9IDAuMDEsCiAgICBiaW5heGlzID0gInkiLCBzdGFja2RpciA9ICJjZW50ZXIiLAogICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNzUpLAogICAgZG90c2l6ZSA9IDEsIGFscGhhID0gMC41LCBjb2xvciA9IE5BLAogICAgc2hvdy5sZWdlbmQgPSBGQUxTRQogICkgKwogIGdlb21fcG9pbnRyYW5nZSgKICAgIGFlcyh4ID0gc2hvcnRlc3RfcGF0aCwgeSA9IGZpdCwgeW1pbiA9IGZpdCAtIHNlLmZpdCwgeW1heCA9IGZpdCArIHNlLmZpdCksCiAgICBkYXRhID0gcHJlZGljdF9uYXZfZGF5MSwgaW5oZXJpdC5hZXMgPSBGQUxTRSwgc2hvdy5sZWdlbmQgPSBGQUxTRSwKICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjE1KSwgbGluZXdpZHRoID0gMQogICkgKwogIGdlb21fbGluZSgKICAgIGFlcyh4ID0gc2hvcnRlc3RfcGF0aCwgeSA9IGZpdCwgZ3JvdXAgPSBtZWFzdXJlbWVudF9pZCksCiAgICBkYXRhID0gcHJlZGljdF9uYXZfZGF5MSwgaW5oZXJpdC5hZXMgPSBGQUxTRSwKICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjE1KSwgbGluZXdpZHRoID0gMQogICkgKwogIHNjYWxlX3hfZGlzY3JldGUobmFtZSA9ICJTaG9ydGVzdCBwYXRoIGRpc3RhbmNlIikgKwogIHNjYWxlX3lfY29udGludW91cygKICAgIG5hbWUgPSAiQWNjdXJhY3kiLCBsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQsIGJyZWFrcyA9IHNlcSgwLCAxLCAwLjEpCiAgKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKDAuNCwgMS4xKSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgZ2d0aXRsZSgiSHVtYW4gc29jaWFsIG5hdmlnYXRpb24iKQoKcGxvdF9uYXZfZGF5MQoKaWYgKGtuaXR0aW5nKSB7CiAgZ2dzYXZlKAogICAgaGVyZSgiZmlndXJlcyIsIHN0cl9jKCJuYXZpZ2F0aW9uX2RheTEiLCAiLnBkZiIpKSwKICAgIHBsb3QgPSBwbG90X25hdl9kYXkxLAogICAgd2lkdGggPSA4LzMsIGhlaWdodCA9IDMsCiAgICB1bml0cyA9ICJpbiIsIGRwaSA9IDMwMAogICkKfQpgYGAKCgojIENvbXB1dGF0aW9uYWwgbW9kZWxzIG9mIHNvY2lhbCBuYXZpZ2F0aW9uCgpXZSdkIGxpa2UgdG8gaGF2ZSBzb21lIG1lY2hhbmlzdGljIGluc2lnaHRzIGFib3V0IGhvdyBwZW9wbGUgc29sdmUgbmF2aWdhdGlvbiBwcm9ibGVtcy4gVG8gZG8gdGhpcywgd2UnbGwgbG9vayBhdCB0d28gY2FuZGlkYXRlIG1vZGVscyBvZiBuYXZpZ2F0aW9uOiBicmVhZHRoLWZpcnN0IHNlYXJjaCAoQkZTKSBhbmQgdGhlIFN1Y2Nlc3NvciBSZXByZXNlbnRhdGlvbiAoU1IpLgoKIyMgU2ltdWxhdGlvbnMKCiMjIyBCRlMgc2ltdWxhdGlvbgoKYGBge3IgbG9hZC1iZnMtZGF0YX0Kc2ltX2JmcyA8LSBoZXJlKCJkYXRhIiwgImJmcy1zaW1zIiwgImJmc19zaW1zX2xlYXJuZWQuY3N2IikgJT4lCiAgcmVhZF9jc3Yoc2hvd19jb2xfdHlwZXMgPSBGQUxTRSkgJT4lCiAgZmlsdGVyKAogICAgdHdvX2NvcnJlY3Rfb3B0aW9ucyA9PSBGQUxTRSwKICAgIHNob3J0ZXN0X3BhdGhfZ2l2ZW5fb3B0cyA9PSBzaG9ydGVzdF9wYXRoX2dpdmVuX3N0YXJ0X2VuZAogICkgJT4lCiAgbXV0YXRlKHNob3J0ZXN0X3BhdGggPSBmYWN0b3Ioc2hvcnRlc3RfcGF0aF9naXZlbl9vcHRzKSkgJT4lCiAgc2VsZWN0KAogICAgc2hvcnRlc3RfcGF0aCwgc3RhcnRwb2ludF9pZCwgZW5kcG9pbnRfaWQsIG9wdDFfaWQsIG9wdDJfaWQsCiAgICBiZnNfY2hvaWNlLCBiZnNfY29ycmVjdF9jaG9pY2UsIGJmc19uX3Zpc2l0c190b3RhbAogICkKYGBgCgpJbiBvdXIgaW1wbGVtZW50YXRpb24sIHdlIG1vZGVsIHRoZSBCRlMgYWdlbnQgaGF2aW5nIHNvbWUgInRocmVzaG9sZCIgZm9yIHNlYXJjaGluZyB0aHJvdWdoIHRoZSBuZXR3b3JrLiBUaGlzIGNhbiBiZSB0aG91Z2h0IG9mIGFzIGEgIndpbGxpbmduZXNzIHRvIHNwZW5kIHRpbWUvZWZmb3J0IHBlcmZvcm1pbmcgYSBzZWFyY2giIHRocmVzaG9sZC4gT25jZSB0aGF0IHRocmVzaG9sZCBpcyBleGNlZWRlZCwgaXQgYmVjb21lcyBpbmNyZWFzaW5nbHkgbGlrZWx5IHRoYXQgdGhlIGFnZW50IGdpdmVzIHVwIGFuZCBjaG9vc2VzIHJhbmRvbWx5LgoKVG8gc2VlIHdoYXQgdGhyZXNob2xkIHZhbHVlcyBtaWdodCBiZSBpbmZvcm1hdGl2ZSB0byBsb29rIGF0LCB3ZSdsbCBsb29rIGF0IHRoZSBhdmVyYWdlIG51bWJlciBvZiAic2VhcmNoZXMiIHRoYXQgYW4gYWdlbnQgbXVzdCBwZXJmb3JtIHRvIG1ha2UgYSAobm9uLXJhbmRvbSkgZGVjaXNpb24uCgpgYGB7ciBhdmctYmZzLXZpc2l0c30Kc2ltX2JmcyAlPiUKICBncm91cF9ieShzaG9ydGVzdF9wYXRoKSAlPiUKICBzdW1tYXJpc2UoYXZnX25fc2VhcmNoZXMgPSBtZWFuKGJmc19uX3Zpc2l0c190b3RhbCkpICU+JQogIGtibCgKICAgIGNhcHRpb24gPSBzdHJfYygiPGNlbnRlcj4iLCAiQXZlcmFnZSBzZWFyY2hlcyBpbiBvbmxpbmUtQkZTIiwgIjwvY2VudGVyPiIpLAogICAgZGlnaXRzID0gMgogICkgJT4lCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInJlc3BvbnNpdmUiKSkKYGBgCgpBbmQgbm93IHdlJ2xsIHBsb3QgdGhlIG1vZGVsIHByZWRpY3Rpb25zLi4uCgpgYGB7ciBwbG90LWJmcy1zaW19CmJmc19hdmdfYWNjdXJhY3kgPC0gc2ltX2JmcyAlPiUKICBncm91cF9ieShzaG9ydGVzdF9wYXRoLCBzdGFydHBvaW50X2lkLCBlbmRwb2ludF9pZCwgb3B0MV9pZCwgb3B0Ml9pZCkgJT4lCiAgc3VtbWFyaXNlKAogICAgYmZzX2FjY3VyYWN5ID0gbWVhbihiZnNfY29ycmVjdF9jaG9pY2UpLAogICAgYmZzX3Zpc2l0cyA9IG1lYW4oYmZzX25fdmlzaXRzX3RvdGFsKSwKICAgIC5ncm91cHMgPSAiZHJvcCIKICApCgpwbG90X3NpbV9iZnMgPC0gYmZzX2F2Z19hY2N1cmFjeSAlPiUKICBleHBhbmRfZ3JpZChzZWFyY2hfdGhyZXNob2xkID0gc2VxKDIsIDEyLCAyKSkgJT4lCiAgcm93d2lzZSgpICU+JQogIG11dGF0ZSgKICAgICMgTm90ZTogcChCRlMpIGlzIDEtcChnaXZlIHVwKQogICAgcF9iZnMgPSBzb2Z0bWF4KAogICAgICBvcHRpb25fdmFsdWVzID0gYyhzZWFyY2hfdGhyZXNob2xkLCBiZnNfdmlzaXRzKSwKICAgICAgb3B0aW9uX2Nob3NlbiA9IDEsCiAgICAgIHRlbXBlcmF0dXJlID0gMQogICAgKQogICkgJT4lCiAgdW5ncm91cCgpICU+JQogICMgV2VpZ2ggdGhlIG1vZGVsIHByZWRpY3Rpb25zIGFjY29yZGluZyB0byB0aGVpciBsaWtlbGlob29kCiAgbXV0YXRlKAogICAgcF9naXZlX3VwID0gMSAtIHBfYmZzLAogICAgYmZzX3RocmVzaG9sZF9hY2N1cmFjeSA9IChwX2JmcyAqIGJmc19hY2N1cmFjeSkgKyAocF9naXZlX3VwICogKDEvMikpCiAgKSAlPiUKICAjIEZvcm1hdCBmb3IgcGxvdHRpbmcKICBtdXRhdGUoCiAgICBzZWFyY2hfdGhyZXNob2xkID0gc3RyX3BhZChzZWFyY2hfdGhyZXNob2xkLCB3aWR0aCA9IDIsIHNpZGUgPSAibGVmdCIpCiAgKSAlPiUKICBiaW5kX3Jvd3MoCiAgICBiZnNfYXZnX2FjY3VyYWN5ICU+JQogICAgICBtdXRhdGUoCiAgICAgICAgc2VhcmNoX3RocmVzaG9sZCA9ICJOZXZlciBnaXZlcyB1cCIsCiAgICAgICAgYmZzX3RocmVzaG9sZF9hY2N1cmFjeSA9IGJmc19hY2N1cmFjeQogICAgICApCiAgKSAlPiUKICAjIE5vdyBwbG90CiAgZ2dwbG90KAogICAgYWVzKAogICAgICB4PXNob3J0ZXN0X3BhdGgsIHk9YmZzX3RocmVzaG9sZF9hY2N1cmFjeSwKICAgICAgY29sb3I9c2VhcmNoX3RocmVzaG9sZCwgZ3JvdXA9c2VhcmNoX3RocmVzaG9sZAogICAgKQogICkgKwogIHRoZW1lX2N1c3RvbSgpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLjUsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBzdGF0X3N1bW1hcnkoZ2VvbSA9ICJsaW5lIiwgZnVuID0gbWVhbiwgbGluZXdpZHRoID0gMSkgKwogIHNjYWxlX3hfZGlzY3JldGUobmFtZSA9ICJTaG9ydGVzdCBwYXRoIGRpc3RhbmNlIikgKwogIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIkFjY3VyYWN5IiwgbGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KSArCiAgc2NhbGVfY29sb3JfdmlyaWRpc19kKAogICAgbmFtZSA9ICJTZWFyY2ggdGhyZXNob2xkIiwgb3B0aW9uID0gIm1hZ21hIiwKICAgIGJlZ2luID0gMC4xLCBlbmQgPSAwLjksIGRpcmVjdGlvbiA9IC0xCiAgKSArCiAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKGJ5cm93ID0gVFJVRSwgbnJvdyA9IDEpKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKDAuNSwgMSkpICsKICB0aGVtZSgKICAgIHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCksCiAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIgogICkgKwogIGdndGl0bGUoIlNpbXVsYXRlZCBCRlMgbmF2aWdhdGlvbiIpCgpwbG90X3NpbV9iZnMKCmlmIChrbml0dGluZykgewogIGdnc2F2ZSgKICAgIGhlcmUoImZpZ3VyZXMiLCBzdHJfYygic2ltdWxhdGVkX2JmcyIsICIucGRmIikpLAogICAgcGxvdCA9IHBsb3Rfc2ltX2JmcywKICAgIHdpZHRoID0gOC8zLCBoZWlnaHQgPSAzLAogICAgdW5pdHMgPSAiaW4iLCBkcGkgPSAzMDAKICApCn0KYGBgCgojIyMgU1IgbmF2aWdhdGlvbiBzaW11bGF0aW9uCgpgYGB7ciBnZXQtdHJpYWxsaXN0fQp0cmlhbGxpc3RfbmF2X2xlYXJuZWQgPC0gbmF2X3N0dWR5MSAlPiUKICBmaWx0ZXIoc3ViX2lkID09IDEpICU+JQogIHNlbGVjdCgKICAgIHN0YXJ0cG9pbnRfaWQsIGVuZHBvaW50X2lkLCBvcHQxX2lkLCBvcHQyX2lkLAogICAgY29ycmVjdF9jaG9pY2UsIHNob3J0ZXN0X3BhdGgKICApICU+JQogIGFycmFuZ2Uoc3RhcnRwb2ludF9pZCwgZW5kcG9pbnRfaWQpCmBgYAoKV2UnbGwgY3JlYXRlIHNvbWUgc2ltdWxhdGVkIGxlYXJuaW5nIG9ic2VydmF0aW9ucy4KCmBgYHtyIHNpbXVsYXRlLW9ic2VydmF0aW9uc30Kc2V0LnNlZWQoc3VtKHV0ZjhUb0ludCgiSmVubnkgYW5kIG1lIHdhcyBsaWtlIHBlYXMgYW5kIGNhcnJvdHMiKSkpCgpzaW11bGF0ZWRfcGFpcmVkX2Fzc29jaWF0ZXMgPC0gYWRqbGlzdCAlPiUKICBmaWx0ZXIoZWRnZSA9PSAxKSAlPiUKICBzZWxlY3QoZnJvbSwgdG8pICU+JQogIGV4cGFuZF9ncmlkKHNldCA9IDE6NTAwMCwgLikgJT4lCiAgZ3JvdXBfYnkoc2V0KSAlPiUKICBzbGljZV9zYW1wbGUocHJvcCA9IDEpICU+JQogIHVuZ3JvdXAoKQpgYGAKCkFuZCBub3cgd2UnbGwgc2ltdWxhdGUgYW4gImFzeW1wdG90aWMiIFNSIGFuZCBob3cgaXQgcGVyZm9ybXMgaW4gdGhlIG5hdmlnYXRpb24gdGFzay4KCmBgYHtyIHNpbS1zci1hc3ltcHRvdGljfQpzaW11bGF0ZV9zciA8LSBmdW5jdGlvbihzaW11bGF0ZWRfb2JzZXJ2YXRpb25zKSB7CiAgc2ltdWxhdGVkX29ic2VydmF0aW9ucyAlPiUKICAgIGV4cGFuZF9ncmlkKGdhbW1hID0gc2VxKDAuMSwgMC45LCAwLjEpKSAlPiUKICAgIGdyb3VwX2J5KGdhbW1hKSAlPiUKICAgIG5lc3QoKSAlPiUKICAgIG11dGF0ZSgKICAgICAgc3IgPSBtYXAoCiAgICAgICAgLnggPSBkYXRhLAogICAgICAgIC5mID0gfmJ1aWxkX3JlcF9zcigKICAgICAgICAgIGxlYXJuaW5nX2RhdGEgPSAueCwgdGhpc19hbHBoYSA9IDAuMSwgdGhpc19nYW1tYSA9IGdhbW1hCiAgICAgICAgKQogICAgICApCiAgICApICU+JQogICAgdW5uZXN0KHNyKSAlPiUKICAgIHVuZ3JvdXAoKSAlPiUKICAgIHNlbGVjdCgtZGF0YSkKfQoKam9pbl9zciA8LSBmdW5jdGlvbihuYXZpZ2F0aW9uX3RyaWFsbGlzdCwgc2ltdWxhdGVkX3NyKSB7CiAgbmF2aWdhdGlvbl90cmlhbGxpc3QgJT4lCiAgICBsZWZ0X2pvaW4oCiAgICAgIHNpbXVsYXRlZF9zciAlPiUKICAgICAgICByZW5hbWUob3B0MV9zciA9IHNyX3ZhbHVlLCBvcHQxX2lkID0gZnJvbSwgZW5kcG9pbnRfaWQgPSB0bykKICAgICkgJT4lCiAgICBsZWZ0X2pvaW4oCiAgICAgIHNpbXVsYXRlZF9zciAlPiUKICAgICAgICByZW5hbWUob3B0Ml9zciA9IHNyX3ZhbHVlLCBvcHQyX2lkID0gZnJvbSwgZW5kcG9pbnRfaWQgPSB0bykKICAgICkKfQoKc2ltX3NyX21hdHJpeF9hc3ltcHRvdGljIDwtIHNpbXVsYXRlZF9wYWlyZWRfYXNzb2NpYXRlcyAlPiUKICBzaW11bGF0ZV9zcigpCgpzaW1fc3JfYmVoYXZpb3JfYXN5bXB0b3RpYyA8LSBqb2luX3NyKAogIHRyaWFsbGlzdF9uYXZfbGVhcm5lZCwgc2ltX3NyX21hdHJpeF9hc3ltcHRvdGljCikgJT4lCiAgIyBGZWVkIHZhbHVlcyB0aHJvdWdoIHNvZnRtYXgKICBtdXRhdGUoYWNyb3NzKGMob3B0MV9zciwgb3B0Ml9zciksIH4ueCAqIDEwMCkpICU+JQogIGV4cGFuZF9ncmlkKHRlbXBlcmF0dXJlID0gMSkgJT4lCiAgcm93d2lzZSgpICU+JQogIG11dGF0ZSgKICAgIHBfY29ycmVjdCA9IHNvZnRtYXgoCiAgICAgIG9wdGlvbl92YWx1ZXMgPSBjKG9wdDFfc3IsIG9wdDJfc3IpLAogICAgICBvcHRpb25fY2hvc2VuID0gaWZfZWxzZShjb3JyZWN0X2Nob2ljZSA9PSBvcHQxX2lkLCAxLCAyKSwKICAgICAgdGVtcGVyYXR1cmUgPSB0ZW1wZXJhdHVyZSwKICAgICAgdXNlX2ludmVyc2VfdGVtcGVyYXR1cmUgPSBUUlVFCiAgICApCiAgKSAlPiUKICB1bmdyb3VwKCkKYGBgCgpgYGB7ciBwbG90LXNyLXNpbS1hc3ltcHRvdGljfQpwbG90X3NpbV9zcl9hc3ltcHRvdGljIDwtIHNpbV9zcl9iZWhhdmlvcl9hc3ltcHRvdGljICU+JQogIG11dGF0ZSgKICAgIGdhbW1hID0gZmFjdG9yKGdhbW1hKSwKICAgIHRlbXBlcmF0dXJlID0gc3RyX3BhZCh0ZW1wZXJhdHVyZSwgd2lkdGggPSAyLCBzaWRlID0gImxlZnQiKSwKICAgIHRlbXBlcmF0dXJlID0gc3RyX2ModW5pY29kZV9ncmVla1sidGF1Il0sICIgPSAiLCB0ZW1wZXJhdHVyZSkKICApICU+JQogIGdyb3VwX2J5KGdhbW1hLCB0ZW1wZXJhdHVyZSwgc2hvcnRlc3RfcGF0aCkgJT4lCiAgc3VtbWFyaXNlKHBfY29ycmVjdCA9IG1lYW4ocF9jb3JyZWN0KSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lCiAgZ2dwbG90KGFlcyh4PXNob3J0ZXN0X3BhdGgsIHk9cF9jb3JyZWN0LCBjb2xvcj1nYW1tYSkpICsKICB0aGVtZV9jdXN0b20oKSArCiAgZmFjZXRfZ3JpZChyb3dzID0gdmFycyh0ZW1wZXJhdHVyZSkpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLjUsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX2xpbmUoYWVzKGNvbG9yID0gZ2FtbWEsIGdyb3VwID0gZ2FtbWEpLCBsaW5ld2lkdGggPSAwLjgpICsKICBzY2FsZV94X2Rpc2NyZXRlKG5hbWUgPSAiU2hvcnRlc3QgcGF0aCBkaXN0YW5jZSIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobmFtZSA9ICJBY2N1cmFjeSIsIGxhYmVscyA9IHNjYWxlczo6cGVyY2VudCkgKwogIHNjYWxlX2NvbG9yX3ZpcmlkaXNfZCgKICAgIG5hbWUgPSBzdHJfYyh1bmljb2RlX2dyZWVrWyJnYW1tYSJdLCAiID0gIiksIG9wdGlvbiA9ICJ0dXJibyIsIGVuZCA9IDAuOQogICkgKwogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChieXJvdyA9IFRSVUUsIG5yb3cgPSAxKSkgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLjUsIDEpKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICBnZ3RpdGxlKCJTaW11bGF0ZWQgU1IgbmF2aWdhdGlvbiIpCgpwbG90X3NpbV9zcl9hc3ltcHRvdGljCgppZiAoa25pdHRpbmcpIHsKICBzdXBwcmVzc1dhcm5pbmdzKAogICAgZ2dzYXZlKAogICAgICBoZXJlKCJmaWd1cmVzIiwgc3RyX2MoInNpbXVsYXRlZF9zciIsICIucGRmIikpLAogICAgICBwbG90ID0gcGxvdF9zaW1fc3JfYXN5bXB0b3RpYywKICAgICAgd2lkdGggPSA4LzMsIGhlaWdodCA9IDMsCiAgICAgIHVuaXRzID0gImluIiwgZHBpID0gMzAwLAogICAgKQogICkKICAKICBnZ3NhdmUoCiAgICBoZXJlKCJmaWd1cmVzIiwgc3RyX2MoInNpbXVsYXRlZF9zcl9jYWlybyIsICIucGRmIikpLAogICAgcGxvdCA9IHBsb3Rfc2ltX3NyX2FzeW1wdG90aWMgKwogICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQoYnlyb3cgPSBUUlVFLCBucm93ID0gMikpLAogICAgd2lkdGggPSA4LzMsIGhlaWdodCA9IDMsCiAgICB1bml0cyA9ICJpbiIsIGRwaSA9IDMwMCwKICAgIGRldmljZSA9IGNhaXJvX3BkZgogICkKfQpgYGAKCiMjIE1vZGVsIGNvbXBhcmlzb24KClRvIGRvIG1vZGVsIGNvbXBhcmlzb24sIHdlJ2xsIG5lZWQgdG8gcHVsbCBpbiB0aGUgZXN0aW1hdGVkIHBhcmFtZXRlcnMvbGlrZWxpaG9vZHMgZnJvbSB0aGUgbW9kZWwtZml0dGluZy4KCmBgYHtyIGxvYWQtcGFyYW1zfQpjbGVhbl9wYXJhbXNfZnJvbV9yYXcgPC0gRkFMU0UKCmlmIChjbGVhbl9wYXJhbXNfZnJvbV9yYXcpIHsKICBwYXJhbXMgPC0gaGVyZSgiZGF0YSIsICJwYXJhbS1maXRzIikgJT4lCiAgICBmczo6ZGlyX2xzKHJlZ2V4cCA9ICJzdHVkeVtbOmRpZ2l0Ol1dX0RbWzpkaWdpdDpdXWI/IikgJT4lCiAgICBtYXBfZGZyKAogICAgICAuZiA9IH5yZWFkX2NzdigueCwgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSkgJT4lCiAgICAgICAgYmVzdF9vcHRpbV9ydW4oImRhdGFmcmFtZSIpLAogICAgICAuaWQgPSAiZmlsZW5hbWUiCiAgICApICU+JQogICAgbXV0YXRlKAogICAgICBzdHVkeSA9IHN0cl9leHRyYWN0KGZpbGVuYW1lLCAic3R1ZHlbWzpkaWdpdDpdXSIpLAogICAgICBzdHVkeSA9IHN0cl9yZW1vdmUoc3R1ZHksICJzdHVkeSIpLAogICAgICBzdHVkeSA9IHN0cl9jKCJTdHVkeSAiLCBzdHVkeSksCiAgICAgIG1lYXN1cmVtZW50X2lkID0gc3RyX2V4dHJhY3QoZmlsZW5hbWUsICJfRFtbOmRpZ2l0Ol1dYj8iKSwKICAgICAgbWVhc3VyZW1lbnRfaWQgPSBzdHJfcmVtb3ZlKG1lYXN1cmVtZW50X2lkLCAiXyIpLAogICAgICBzdWJfaWQgPSBzdHJfZXh0cmFjdChmaWxlbmFtZSwgInN1Yi1bWzpkaWdpdDpdXSsiKSwKICAgICAgc3ViX2lkID0gc3RyX3JlbW92ZShzdWJfaWQsICJzdWItIiksCiAgICAgIHN1Yl9pZCA9IGFzLmludGVnZXIoc3ViX2lkKSwKICAgICAgbW9kZWwgPSBjYXNlX3doZW4oCiAgICAgICAgc3RyX2RldGVjdChmaWxlbmFtZSwgIl9oeWJyaWQtIikgfiAiaHlicmlkIiwKICAgICAgICBzdHJfZGV0ZWN0KGZpbGVuYW1lLCAiX3NyLSIpIH4gInNyIiwKICAgICAgICBzdHJfZGV0ZWN0KGZpbGVuYW1lLCAiX2Jmcy0iKSB+ICJiZnMiCiAgICAgICkKICAgICkgJT4lCiAgICBzZWxlY3QoCiAgICAgIHN0dWR5LCBzdWJfaWQsIG1lYXN1cmVtZW50X2lkLAogICAgICBtb2RlbCwKICAgICAgcGFyYW1fbmFtZSwgcGFyYW1fdmFsdWUgPSBwYXJhbV92YWx1ZV9odW1hbl9yZWFkYWJsZSwKICAgICAgbmVnX2xvZ2xpayA9IG9wdGltX3ZhbHVlCiAgICApICU+JQogICAgYXJyYW5nZShzdHVkeSwgc3ViX2lkLCBtZWFzdXJlbWVudF9pZCwgbW9kZWwpCiAgCiAgcGFyYW1zICU+JQogICAgd3JpdGVfY3N2KGhlcmUoImRhdGEiLCAicGFyYW0tZml0cyIsICJjbGVhbl9wYXJhbV9maXRzLmNzdiIpKQp9IGVsc2UgewogIHBhcmFtcyA8LSBoZXJlKCJkYXRhIiwgInBhcmFtLWZpdHMiLCAiY2xlYW5fcGFyYW1fZml0cy5jc3YiKSAlPiUKICAgIHJlYWRfY3N2KHNob3dfY29sX3R5cGVzID0gRkFMU0UpCn0KYGBgCgpgYGB7ciBweHAtbW9kZWwtc2VsZWN0aW9ufQpzb3VyY2UoaGVyZSgiY29kZSIsICJ1dGlscyIsICJiYXllc2lhbl9tb2RlbF9zZWxlY3Rpb24uUiIpKQoKcHhwX3Jlc3VsdHMgPC0gcGFyYW1zICU+JQogIHNlbGVjdChzdHVkeSwgc3ViX2lkLCBtZWFzdXJlbWVudF9pZCwgbW9kZWwsIG5lZ19sb2dsaWspICU+JQogIGRpc3RpbmN0KCkgJT4lCiAgbXV0YXRlKGxvZ19saWsgPSAtbmVnX2xvZ2xpaykgJT4lCiAgc2VsZWN0KC1uZWdfbG9nbGlrKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gbW9kZWwsIHZhbHVlc19mcm9tID0gbG9nX2xpaykgJT4lCiAgc2VsZWN0KC1zdWJfaWQpICU+JQogIGdyb3VwX2J5KHN0dWR5LCBtZWFzdXJlbWVudF9pZCkgJT4lCiAgbmVzdCgpICU+JQogIG11dGF0ZSgKICAgIHRlc3QgPSBtYXAoCiAgICAgIC54ID0gZGF0YSwKICAgICAgLmYgPSB+YmF5ZXNpYW5fbW9kZWxfc2VsZWN0aW9uKC54KQogICAgKQogICkgJT4lCiAgdW5uZXN0KHRlc3QpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBzZWxlY3QoLWRhdGEpCgpweHBfcmVzdWx0cyAlPiUKICBnZ3Bsb3QoYWVzKHg9bWVhc3VyZW1lbnRfaWQsIHk9cHhwLCBjb2xvcj1tb2RlbCkpICsKICB0aGVtZV9jdXN0b20oKSArCiAgZmFjZXRfd3JhcCh+c3R1ZHksIHNjYWxlcyA9ICJmcmVlX3giKSArCiAgZ2VvbV9wb2ludCgKICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjc1KQogICkKCnB4cF9yZXN1bHRzICU+JQogIHNlbGVjdChzdHVkeSwgbWVhc3VyZW1lbnRfaWQsIG1vZGVsLCBweHApICU+JQogIG11dGF0ZShweHAgPSBhcy5udW1lcmljKHB4cCkpICU+JQogIHBpdm90X3dpZGVyKAogICAgbmFtZXNfZnJvbSA9IG1vZGVsLAogICAgdmFsdWVzX2Zyb20gPSBweHAsCiAgICBuYW1lc19wcmVmaXggPSAicHhwXyIKICApICU+JQogIGtibCgKICAgIGNhcHRpb24gPSBzdHJfYygiPGNlbnRlcj4iLCAiUFhQIHJlc3VsdHMiLCAiPC9jZW50ZXI+IiksCiAgICBkaWdpdHMgPSAzCiAgKSAlPiUKICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygicmVzcG9uc2l2ZSIpKQpgYGAKCiMjIFBvc3RlcmlvciBwcmVkaWN0aXZlIGNoZWNrCgpXZSdsbCBzdGFydCBieSBzaW11bGF0aW5nIHRoZSBtb2RlbCdzIHByZWRpY3Rpb25zIGZvciBlYWNoIHN1YmplY3QsIGdpdmVuIHRoZWlyIGVzdGltYXRlZCBwYXJhbWV0ZXJzLgoKYGBge3IgcHBjLWJmc30KcHBjX2JmcyA8LSBiaW5kX3Jvd3MobmF2X3N0dWR5MSwgbmF2X3N0dWR5MiwgbmF2X3N0dWR5MykgJT4lCiAgZmlsdGVyKG1lYXN1cmVtZW50X2lkICVpbiUgYygiRDEiLCAiRDIiKSkgJT4lCiAgbGVmdF9qb2luKAogICAgcGFyYW1zICU+JQogICAgICBmaWx0ZXIobW9kZWwgPT0gImJmcyIpICU+JQogICAgICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gcGFyYW1fbmFtZSwgdmFsdWVzX2Zyb20gPSBwYXJhbV92YWx1ZSkgJT4lCiAgICAgIHNlbGVjdChzdHVkeSwgc3ViX2lkLCBtZWFzdXJlbWVudF9pZCwgc2VhcmNoX3RocmVzaG9sZCwgbGFwc2VfcmF0ZSkKICApICU+JQogIGxlZnRfam9pbihiZnNfYXZnX2FjY3VyYWN5KSAlPiUKICBtdXRhdGUoCiAgICBwX3N1Yl9jaG9pY2VfYmZzID0gaWZfZWxzZSgKICAgICAgc3ViX2Nob2ljZSA9PSBjb3JyZWN0X2Nob2ljZSwKICAgICAgYmZzX2FjY3VyYWN5LAogICAgICAxIC0gYmZzX2FjY3VyYWN5CiAgICApCiAgKSAlPiUKICAjIFdoYXQncyB0aGUgcHJvYmFiaWxpdHkgb2YgKmNvbXBsZXRpbmcqIEJGUy1vbmxpbmUgYWxsIHRoZSB3YXkgdGhyb3VnaD8KICByb3d3aXNlKCkgJT4lCiAgbXV0YXRlKAogICAgc2VhcmNoX3RocmVzaG9sZCA9IHNlYXJjaF90aHJlc2hvbGQsCiAgICBwX2NvbXBsZXRlX2JmcyA9IHNvZnRtYXgoCiAgICAgIG9wdGlvbl92YWx1ZXMgPSBjKHNlYXJjaF90aHJlc2hvbGQsIGJmc192aXNpdHMpLAogICAgICBvcHRpb25fY2hvc2VuID0gMSwKICAgICAgdGVtcGVyYXR1cmUgPSAxCiAgICApCiAgKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgIyBXZWlnaCBCRlMgcHJlZGljdGlvbnMgYWNjb3JkaW5nbHkKICBtdXRhdGUoCiAgICBwX2dpdmVfdXAgPSAxIC0gcF9jb21wbGV0ZV9iZnMsCiAgICBwcmVkaWN0ZWRfY29ycmVjdCA9IChwX2NvbXBsZXRlX2JmcyAqIHBfc3ViX2Nob2ljZV9iZnMpICsgKHBfZ2l2ZV91cCAqIDEvMiksCiAgICAjIyMgQWRkIGxhcHNlIHJhdGUKICAgICMgICBEaXZpZGluZyBieSAyIGlzIGJlY2F1c2UgdGhlcmUgYXJlIHR3byBvcHRpb25zIHRvIGNob29zZSBmcm9tCiAgICAjICAgVGhlcmVmb3JlLCB3aGVuIGxhcHNlIHJhdGUgPSAxLCB0aGlzIGJlY29tZXMgY2hhbmNlID0gMS8yCiAgICBwcmVkaWN0ZWRfY29ycmVjdCA9IHByZWRpY3RlZF9jb3JyZWN0ICogKDEtbGFwc2VfcmF0ZSkgKyAobGFwc2VfcmF0ZS8yKQogICkgJT4lCiAgIyBBdmVyYWdlIG92ZXIgdHJpYWxzCiAgZ3JvdXBfYnkoc3R1ZHksIHN1Yl9pZCwgbWVhc3VyZW1lbnRfaWQsIHNob3J0ZXN0X3BhdGgpICU+JQogIHN1bW1hcmlzZSgKICAgIGVtcGlyaWNhbCA9IG1lYW4oY29ycmVjdCksCiAgICBwcmVkaWN0ZWQgPSBtZWFuKHByZWRpY3RlZF9jb3JyZWN0KSwKICAgIC5ncm91cHMgPSAiZHJvcCIKICApCmBgYAoKYGBge3IgcHBjLXNyfQpwcGNfc3JfbWF0cml4IDwtIHBhcmFtcyAlPiUKICBmaWx0ZXIobW9kZWwgPT0gInNyIikgJT4lCiAgc2VsZWN0KAogICAgc3R1ZHksIHN1Yl9pZCwgbWVhc3VyZW1lbnRfaWQsIG5hbWUgPSBwYXJhbV9uYW1lLCB2YWx1ZSA9IHBhcmFtX3ZhbHVlCiAgKSAlPiUKICBwaXZvdF93aWRlcigpICU+JQogIGdyb3VwX2J5KHN0dWR5LCBzdWJfaWQsIG1lYXN1cmVtZW50X2lkKSAlPiUKICBuZXN0KCkgJT4lCiAgbXV0YXRlKAogICAgc2ltX3NyID0gbWFwKAogICAgICAueCA9IGRhdGEsCiAgICAgIC5mID0gfmJ1aWxkX3JlcF9zcigKICAgICAgICBsZWFybmluZ19kYXRhID0gc2ltdWxhdGVkX3BhaXJlZF9hc3NvY2lhdGVzICU+JSBmaWx0ZXIoc2V0ICVpbiUgMToxMDApLAogICAgICAgIHRoaXNfYWxwaGEgPSAwLjEsCiAgICAgICAgdGhpc19nYW1tYSA9IC54JHNyX2dhbW1hLAogICAgICAgIGJpZGlyZWN0aW9uYWwgPSBUUlVFCiAgICAgICkKICAgICkKICApICU+JQogIHVubmVzdChzaW1fc3IpICU+JQogIHVubmVzdChkYXRhKSAlPiUKICB1bmdyb3VwKCkKCnBwY19zcl9iZWhhdmlvciA8LSBiaW5kX3Jvd3MobmF2X3N0dWR5MSwgbmF2X3N0dWR5MiwgbmF2X3N0dWR5MykgJT4lCiAgZmlsdGVyKG1lYXN1cmVtZW50X2lkICVpbiUgYygiRDEiLCAiRDIiKSkgJT4lCiAgbGVmdF9qb2luKAogICAgcHBjX3NyX21hdHJpeCAlPiUKICAgICAgcmVuYW1lKG9wdDFfaWQgPSBmcm9tLCBlbmRwb2ludF9pZCA9IHRvLCBvcHQxX3NyID0gc3JfdmFsdWUpCiAgKSAlPiUKICBsZWZ0X2pvaW4oCiAgICBwcGNfc3JfbWF0cml4ICU+JQogICAgICByZW5hbWUob3B0Ml9pZCA9IGZyb20sIGVuZHBvaW50X2lkID0gdG8sIG9wdDJfc3IgPSBzcl92YWx1ZSkKICApICU+JQogIHJvd3dpc2UoKSAlPiUKICBtdXRhdGUoCiAgICBwcmVkaWN0ZWRfY29ycmVjdCA9IHNvZnRtYXgoCiAgICAgIG9wdGlvbl92YWx1ZXMgPSBjKG9wdDFfc3IsIG9wdDJfc3IpICogMTAwLAogICAgICBvcHRpb25fY2hvc2VuID0gaWZfZWxzZShjb3JyZWN0X2Nob2ljZSA9PSBvcHQxX2lkLCAxLCAyKSwKICAgICAgdGVtcGVyYXR1cmUgPSBzb2Z0bWF4X3RlbXBlcmF0dXJlLAogICAgICB1c2VfaW52ZXJzZV90ZW1wZXJhdHVyZSA9IFRSVUUsCiAgICAgIGxhcHNlX3JhdGUgPSBsYXBzZV9yYXRlCiAgICApCiAgKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgIyBGaXggdHJpYWxzIHdoZW4gdGhlIHNvZnRtYXggYmVjb21lcyB1bmRlZmluZWQKICBtdXRhdGUoCiAgICBwcmVkaWN0ZWRfY29ycmVjdCA9IGNhc2Vfd2hlbigKICAgICAgaXMubmFuKHByZWRpY3RlZF9jb3JyZWN0KSAmIChzdWJfY2hvaWNlID09IGNvcnJlY3RfY2hvaWNlKSB+IDEsCiAgICAgIGlzLm5hbihwcmVkaWN0ZWRfY29ycmVjdCkgJiAoc3ViX2Nob2ljZSAhPSBjb3JyZWN0X2Nob2ljZSkgfiAwLAogICAgICBUUlVFIH4gcHJlZGljdGVkX2NvcnJlY3QKICAgICkKICApICU+JQogICMgQXZlcmFnZSBvdmVyIHRyaWFscwogIGdyb3VwX2J5KHN0dWR5LCBzdWJfaWQsIG1lYXN1cmVtZW50X2lkLCBzaG9ydGVzdF9wYXRoKSAlPiUKICBzdW1tYXJpc2UoCiAgICBlbXBpcmljYWwgPSBtZWFuKGNvcnJlY3QpLAogICAgcHJlZGljdGVkID0gbWVhbihwcmVkaWN0ZWRfY29ycmVjdCksCiAgICAuZ3JvdXBzID0gImRyb3AiCiAgKQpgYGAKCk5vdyB0aGF0IHdlIGhhdmUgYm90aCBQUENzLCB3ZSBjYW4gcGxvdCB0aGVtIHNpZGUtYnktc2lkZS4KCmBgYHtyIHBsb3QtcHBjLWRheTF9CnBsb3RfcHBjX2RheTEgPC0gcHBjX2JmcyAlPiUKICByZW5hbWUocHJlZGljdGVkX2JmcyA9IHByZWRpY3RlZCkgJT4lCiAgbGVmdF9qb2luKHBwY19zcl9iZWhhdmlvciAlPiUgcmVuYW1lKHByZWRpY3RlZF9zciA9IHByZWRpY3RlZCkpICU+JQogIHBpdm90X2xvbmdlcigKICAgIGMoZW1waXJpY2FsLCBwcmVkaWN0ZWRfYmZzLCBwcmVkaWN0ZWRfc3IpLAogICAgbmFtZXNfdG8gPSAiYWdlbnQiLCB2YWx1ZXNfdG8gPSAiYWNjdXJhY3kiCiAgKSAlPiUKICBmaWx0ZXIobWVhc3VyZW1lbnRfaWQgPT0gIkQxIikgJT4lCiAgZ2dwbG90KGFlcyh4PXNob3J0ZXN0X3BhdGgsIHk9YWNjdXJhY3kpKSArCiAgdGhlbWVfY3VzdG9tKCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAuNSwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21fcG9pbnQoCiAgICBhZXMoY29sb3IgPSBhZ2VudCksCiAgICBhbHBoYSA9IDAuMDUsCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcmRvZGdlKAogICAgICBqaXR0ZXIud2lkdGggPSAwLjIsIGppdHRlci5oZWlnaHQgPSAwLCBkb2RnZS53aWR0aCA9IDAuNzUsIHNlZWQgPSAxCiAgICApLAogICAgc2hvdy5sZWdlbmQgPSBGQUxTRQogICkgKwogIHN0YXRfc3VtbWFyeSgKICAgIGFlcyhjb2xvciA9IGFnZW50KSwgZ2VvbSA9ICJjcm9zc2JhciIsIGZ1biA9IG1lYW4sCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuNSkKICApICsKICBzY2FsZV94X2Rpc2NyZXRlKG5hbWUgPSAiU2hvcnRlc3QgcGF0aCBkaXN0YW5jZSIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoCiAgICBuYW1lID0gIkFjY3VyYWN5IiwgbGFiZWxzID0gc2NhbGVzOjpwZXJjZW50LCBicmVha3MgPSBzZXEoMCwgMSwgMC4yNSkKICApICsKICBzY2FsZV9jb2xvcl9tYW51YWwoCiAgICBuYW1lID0gTlVMTCwKICAgIHZhbHVlcyA9IGMoCiAgICAgICJlbXBpcmljYWwiPSIjZmQ4ZDNjIiwKICAgICAgInByZWRpY3RlZF9iZnMiPSIjOGMyZDA0IiwKICAgICAgInByZWRpY3RlZF9zciI9IiNiZDAwMjYiCiAgICApLAogICAgbGFiZWxzID0gYygiZW1waXJpY2FsIj0iSHVtYW4iLCAicHJlZGljdGVkX2JmcyI9IkJGUyIsICJwcmVkaWN0ZWRfc3IiPSJTUiIpCiAgKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICBnZ3RpdGxlKCJQb3N0ZXJpb3IgcHJlZGljdGl2ZSBjaGVjayIpCgpwbG90X3BwY19kYXkxCgppZiAoa25pdHRpbmcpIHsKICBnZ3NhdmUoCiAgICBoZXJlKCJmaWd1cmVzIiwgc3RyX2MoInBwY19kYXkxIiwgIi5wZGYiKSksCiAgICBwbG90ID0gcGxvdF9wcGNfZGF5MSwKICAgIHdpZHRoID0gOC8yLCBoZWlnaHQgPSAyLjUsCiAgICB1bml0cyA9ICJpbiIsIGRwaSA9IDMwMAogICkKfQpgYGAKCiMjIEhlbGQtb3V0IHRyaWFscwoKVGhlcmUgd2VyZSBzb21lIHRyaWFscyB3aGVyZSBib3RoIFNvdXJjZXMgaGFkIGVxdWl2YWxlbnQgc2hvcnRlc3QgcGF0aCBkaXN0YW5jZXMgZnJvbSB0aGUgVGFyZ2V0LiBXZSB3b3VsZCBleHBlY3QgdGhhdCBCRlMgd291bGQgYmUgbGFyZ2VseSBpbmRpZmZlcmVudCBiZXR3ZWVuIHRoZSB0d28gU291cmNlcywgYnV0IGl0IGlzIHBvc3NpYmxlIHRoYXQgaHVtYW5zIGFuZC9vciB0aGUgU1Igd291bGQgbWFrZSBvdGhlciBwcmVkaWN0aW9ucy4KCmBgYHtyIGxvYWQtdGllLWRhdGF9Cm5hdl9zdHVkeTFfdGllcyA8LSBoZXJlKCJkYXRhIiwgImNsZWFuLWRhdGEiLCAic3R1ZHkxX21lc3NhZ2VfcGFzc2luZy5jc3YiKSAlPiUKICByZWFkX2NzdihzaG93X2NvbF90eXBlcyA9IEZBTFNFKSAlPiUKICBmaWx0ZXIoCiAgICB0d29fY29ycmVjdF9vcHRpb25zID09IFRSVUUsCiAgICBzaG9ydGVzdF9wYXRoX2dpdmVuX29wdHMgPT0gc2hvcnRlc3RfcGF0aF9naXZlbl9zdGFydF9lbmQKICApICU+JQogIG11dGF0ZSgKICAgIHN0dWR5ID0gIlN0dWR5IDEiLAogICAgbWVhc3VyZW1lbnRfaWQgPSBzdHJfYygiRCIsIG1lYXN1cmVtZW50X2lkKSwKICAgIHNob3J0ZXN0X3BhdGggPSBmYWN0b3Ioc2hvcnRlc3RfcGF0aF9naXZlbl9vcHRzKQogICkgJT4lCiAgc2VsZWN0KAogICAgc3R1ZHksIHN1Yl9pZCwgbWVhc3VyZW1lbnRfaWQsIHNob3J0ZXN0X3BhdGgsCiAgICBzdGFydHBvaW50X2lkLCBlbmRwb2ludF9pZCwKICAgIG9wdDFfaWQsIG9wdDJfaWQsCiAgICBjb3JyZWN0X2Nob2ljZSwgc3ViX2Nob2ljZSwKICAgIGNvcnJlY3QsIHJ0CiAgKSAlPiUKICBmaWx0ZXIobWVhc3VyZW1lbnRfaWQgJWluJSBjKCJEMSIsICJEMiIpKQoKbmF2X3N0dWR5Ml90aWVzIDwtIGhlcmUoImRhdGEiLCAiY2xlYW4tZGF0YSIsICJzdHVkeTJfbWVzc2FnZV9wYXNzaW5nLmNzdiIpICU+JQogIHJlYWRfY3N2KHNob3dfY29sX3R5cGVzID0gRkFMU0UpICU+JQogIGZpbHRlcigKICAgIHR3b19jb3JyZWN0X29wdGlvbnMgPT0gVFJVRSwKICAgIHNob3J0ZXN0X3BhdGhfZ2l2ZW5fb3B0cyA9PSBzaG9ydGVzdF9wYXRoX2dpdmVuX3N0YXJ0X2VuZAogICkgJT4lCiAgbXV0YXRlKAogICAgc3R1ZHkgPSAiU3R1ZHkgMiIsCiAgICBtZWFzdXJlbWVudF9pZCA9IGNhc2Vfd2hlbigKICAgICAgbmV0d29yayA9PSAibGVhcm5lZCIgfiBzdHJfYygiRCIsIG1lYXN1cmVtZW50X2lkKSwKICAgICAgbmV0d29yayA9PSAicmVldmFsdWF0ZWQiIH4gIkQyYiIKICAgICksCiAgICBzaG9ydGVzdF9wYXRoID0gZmFjdG9yKHNob3J0ZXN0X3BhdGhfZ2l2ZW5fb3B0cykKICApICU+JQogIHNlbGVjdCgKICAgIHN0dWR5LCBzdWJfaWQsIG1lYXN1cmVtZW50X2lkLCBzaG9ydGVzdF9wYXRoLAogICAgc3RhcnRwb2ludF9pZCwgZW5kcG9pbnRfaWQsCiAgICBvcHQxX2lkLCBvcHQyX2lkLAogICAgY29ycmVjdF9jaG9pY2UsIHN1Yl9jaG9pY2UsCiAgICBjb3JyZWN0LCBydAogICkgJT4lCiAgZmlsdGVyKG1lYXN1cmVtZW50X2lkICVpbiUgYygiRDEiLCAiRDIiKSkKCm5hdl9zdHVkeTNfdGllcyA8LSBoZXJlKCJkYXRhIiwgImNsZWFuLWRhdGEiLCAic3R1ZHkzX21lc3NhZ2VfcGFzc2luZy5jc3YiKSAlPiUKICByZWFkX2NzdihzaG93X2NvbF90eXBlcyA9IEZBTFNFKSAlPiUKICBmaWx0ZXIoCiAgICB0d29fY29ycmVjdF9vcHRpb25zID09IFRSVUUsCiAgICBzaG9ydGVzdF9wYXRoX2dpdmVuX29wdHMgPT0gc2hvcnRlc3RfcGF0aF9naXZlbl9zdGFydF9lbmQKICApICU+JQogIG11dGF0ZSgKICAgIHN0dWR5ID0gIlN0dWR5IDMiLAogICAgbWVhc3VyZW1lbnRfaWQgPSBjYXNlX3doZW4oCiAgICAgIG5ldHdvcmsgPT0gInJlZXZhbHVhdGVkIiB+ICJEMmIiLAogICAgICBtZWFzdXJlbWVudF9pZCA9PSAxIH4gIkQxIiwKICAgICAgbWVhc3VyZW1lbnRfaWQgPT0gMiB+ICJEMWIiLAogICAgICBtZWFzdXJlbWVudF9pZCA9PSAzIH4gIkQyIgogICAgKSwKICAgIHNob3J0ZXN0X3BhdGggPSBmYWN0b3Ioc2hvcnRlc3RfcGF0aF9naXZlbl9vcHRzKQogICkgJT4lCiAgc2VsZWN0KAogICAgc3R1ZHksIHN1Yl9pZCwgbWVhc3VyZW1lbnRfaWQsIHNob3J0ZXN0X3BhdGgsCiAgICBzdGFydHBvaW50X2lkLCBlbmRwb2ludF9pZCwKICAgIG9wdDFfaWQsIG9wdDJfaWQsCiAgICBjb3JyZWN0X2Nob2ljZSwgc3ViX2Nob2ljZSwKICAgIGNvcnJlY3QsIHJ0CiAgKSAlPiUKICBmaWx0ZXIobWVhc3VyZW1lbnRfaWQgJWluJSBjKCJEMSIsICJEMiIpKQpgYGAKCmBgYHtyIHRpZXMtaHVtYW59CnRpZV9pdGVtX2FuYWx5c2lzX2h1bWFucyA8LSBiaW5kX3Jvd3MoCiAgbmF2X3N0dWR5MV90aWVzLCBuYXZfc3R1ZHkyX3RpZXMsIG5hdl9zdHVkeTNfdGllcwopICU+JQogIGZpbHRlcihtZWFzdXJlbWVudF9pZCA9PSAiRDEiKSAlPiUKICBncm91cF9ieShzaG9ydGVzdF9wYXRoLCBzdGFydHBvaW50X2lkLCBlbmRwb2ludF9pZCwgb3B0MV9pZCwgb3B0Ml9pZCkgJT4lCiAgc3VtbWFyaXNlKAogICAgcF9odW1hbl9vcHQxID0gbWVhbihzdWJfY2hvaWNlID09IG9wdDFfaWQpLAogICAgLmdyb3VwcyA9ICJkcm9wIgogICkKYGBgCgpgYGB7ciB0aWVzLWJmc30KYmZzX2F2Z19hY2N1cmFjeV90aWVzIDwtIGhlcmUoImRhdGEiLCAiYmZzLXNpbXMiLCAiYmZzX3NpbXNfbGVhcm5lZC5jc3YiKSAlPiUKICByZWFkX2NzdihzaG93X2NvbF90eXBlcyA9IEZBTFNFKSAlPiUKICBmaWx0ZXIoCiAgICB0d29fY29ycmVjdF9vcHRpb25zID09IFRSVUUsCiAgICBzaG9ydGVzdF9wYXRoX2dpdmVuX29wdHMgPT0gc2hvcnRlc3RfcGF0aF9naXZlbl9zdGFydF9lbmQKICApICU+JQogIG11dGF0ZShzaG9ydGVzdF9wYXRoID0gZmFjdG9yKHNob3J0ZXN0X3BhdGhfZ2l2ZW5fb3B0cykpICU+JQogIHNlbGVjdCgKICAgIHNob3J0ZXN0X3BhdGgsIHN0YXJ0cG9pbnRfaWQsIGVuZHBvaW50X2lkLCBvcHQxX2lkLCBvcHQyX2lkLAogICAgYmZzX2Nob2ljZSwgYmZzX2NvcnJlY3RfY2hvaWNlLCBiZnNfbl92aXNpdHNfdG90YWwKICApICU+JQogIGdyb3VwX2J5KHNob3J0ZXN0X3BhdGgsIHN0YXJ0cG9pbnRfaWQsIGVuZHBvaW50X2lkLCBvcHQxX2lkLCBvcHQyX2lkKSAlPiUKICBzdW1tYXJpc2UoCiAgICBwX2Jmc19vcHQxID0gbWVhbihiZnNfY2hvaWNlID09IG9wdDFfaWQpLAogICAgYmZzX3Zpc2l0cyA9IG1lYW4oYmZzX25fdmlzaXRzX3RvdGFsKSwKICAgIC5ncm91cHMgPSAiZHJvcCIKICApCgp0aWVfaXRlbV9hbmFseXNpc19iZnMgPC0gYmluZF9yb3dzKAogIG5hdl9zdHVkeTFfdGllcywgbmF2X3N0dWR5Ml90aWVzLCBuYXZfc3R1ZHkzX3RpZXMKKSAlPiUKICBmaWx0ZXIobWVhc3VyZW1lbnRfaWQgPT0gIkQxIikgJT4lCiAgbGVmdF9qb2luKAogICAgcGFyYW1zICU+JQogICAgICBmaWx0ZXIobW9kZWwgPT0gImJmcyIpICU+JQogICAgICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gcGFyYW1fbmFtZSwgdmFsdWVzX2Zyb20gPSBwYXJhbV92YWx1ZSkgJT4lCiAgICAgIHNlbGVjdChzdHVkeSwgc3ViX2lkLCBtZWFzdXJlbWVudF9pZCwgc2VhcmNoX3RocmVzaG9sZCwgbGFwc2VfcmF0ZSkKICApICU+JQogIGxlZnRfam9pbihiZnNfYXZnX2FjY3VyYWN5X3RpZXMpICU+JQogIG11dGF0ZSgKICAgIHBfc3ViX2Nob2ljZV9iZnMgPSBpZl9lbHNlKAogICAgICBzdWJfY2hvaWNlID09IG9wdDFfaWQsCiAgICAgIHBfYmZzX29wdDEsCiAgICAgIDEgLSBwX2Jmc19vcHQxCiAgICApCiAgKSAlPiUKICBzZWxlY3QoLXBfYmZzX29wdDEpICU+JQogICMgV2hhdCdzIHRoZSBwcm9iYWJpbGl0eSBvZiAqY29tcGxldGluZyogQkZTLW9ubGluZSBhbGwgdGhlIHdheSB0aHJvdWdoPwogIHJvd3dpc2UoKSAlPiUKICBtdXRhdGUoCiAgICBzZWFyY2hfdGhyZXNob2xkID0gc2VhcmNoX3RocmVzaG9sZCwKICAgIHBfY29tcGxldGVfYmZzID0gc29mdG1heCgKICAgICAgb3B0aW9uX3ZhbHVlcyA9IGMoc2VhcmNoX3RocmVzaG9sZCwgYmZzX3Zpc2l0cyksCiAgICAgIG9wdGlvbl9jaG9zZW4gPSAxLAogICAgICB0ZW1wZXJhdHVyZSA9IDEKICAgICkKICApICU+JQogIHVuZ3JvdXAoKSAlPiUKICAjIFdlaWdoIEJGUyBwcmVkaWN0aW9ucyBhY2NvcmRpbmdseQogIG11dGF0ZSgKICAgIHBfZ2l2ZV91cCA9IDEgLSBwX2NvbXBsZXRlX2JmcywKICAgIHBfYmZzX29wdDEgPSAocF9jb21wbGV0ZV9iZnMgKiBwX3N1Yl9jaG9pY2VfYmZzKSArIChwX2dpdmVfdXAgKiAxLzIpLAogICAgIyMjIEFkZCBsYXBzZSByYXRlCiAgICAjICAgRGl2aWRpbmcgYnkgMiBpcyBiZWNhdXNlIHRoZXJlIGFyZSB0d28gb3B0aW9ucyB0byBjaG9vc2UgZnJvbQogICAgIyAgIFRoZXJlZm9yZSwgd2hlbiBsYXBzZSByYXRlID0gMSwgdGhpcyBiZWNvbWVzIGNoYW5jZSA9IDEvMgogICAgcF9iZnNfb3B0MSA9IHBfYmZzX29wdDEgKiAoMS1sYXBzZV9yYXRlKSArIChsYXBzZV9yYXRlLzIpCiAgKSAlPiUKICAjIEF2ZXJhZ2Ugb3ZlciB0cmlhbHMKICAjIGdyb3VwX2J5KHNob3J0ZXN0X3BhdGgpICU+JQogIGdyb3VwX2J5KHNob3J0ZXN0X3BhdGgsIHN0YXJ0cG9pbnRfaWQsIGVuZHBvaW50X2lkLCBvcHQxX2lkLCBvcHQyX2lkKSAlPiUKICBzdW1tYXJpc2UoCiAgICBwX2Jmc19vcHQxID0gbWVhbihwX2Jmc19vcHQxKSwKICAgIC5ncm91cHMgPSAiZHJvcCIKICApCmBgYAoKYGBge3IgdGllcy1zcn0KdGllX2l0ZW1fYW5hbHlzaXNfc3IgPC0gYmluZF9yb3dzKAogIG5hdl9zdHVkeTFfdGllcywgbmF2X3N0dWR5Ml90aWVzLCBuYXZfc3R1ZHkzX3RpZXMKKSAlPiUKICBmaWx0ZXIobWVhc3VyZW1lbnRfaWQgPT0gIkQxIikgJT4lCiAgbGVmdF9qb2luKAogICAgcHBjX3NyX21hdHJpeCAlPiUKICAgICAgc2VsZWN0KAogICAgICAgIHN0dWR5LCBzdWJfaWQsIG1lYXN1cmVtZW50X2lkLAogICAgICAgIG9wdDFfaWQgPSBmcm9tLAogICAgICAgIGVuZHBvaW50X2lkID0gdG8sCiAgICAgICAgb3B0MV9zciA9IHNyX3ZhbHVlCiAgICAgICkKICApICU+JQogIGxlZnRfam9pbigKICAgIHBwY19zcl9tYXRyaXggJT4lCiAgICAgIHNlbGVjdCgKICAgICAgICBzdHVkeSwgc3ViX2lkLCBtZWFzdXJlbWVudF9pZCwKICAgICAgICBvcHQyX2lkID0gZnJvbSwKICAgICAgICBlbmRwb2ludF9pZCA9IHRvLAogICAgICAgIG9wdDJfc3IgPSBzcl92YWx1ZSwKICAgICAgICBzcl9nYW1tYSwgc29mdG1heF90ZW1wZXJhdHVyZSwgbGFwc2VfcmF0ZQogICAgICApCiAgKSAlPiUKICByb3d3aXNlKCkgJT4lCiAgbXV0YXRlKAogICAgcF9zcl9vcHQxID0gc29mdG1heCgKICAgICAgb3B0aW9uX3ZhbHVlcyA9IGMob3B0MV9zciwgb3B0Ml9zcikgKiAxMDAsCiAgICAgIG9wdGlvbl9jaG9zZW4gPSAxLAogICAgICB0ZW1wZXJhdHVyZSA9IHNvZnRtYXhfdGVtcGVyYXR1cmUsCiAgICAgIHVzZV9pbnZlcnNlX3RlbXBlcmF0dXJlID0gVFJVRSwKICAgICAgbGFwc2VfcmF0ZSA9IGxhcHNlX3JhdGUKICAgICkKICApICU+JQogIGdyb3VwX2J5KHNob3J0ZXN0X3BhdGgsIHN0YXJ0cG9pbnRfaWQsIGVuZHBvaW50X2lkLCBvcHQxX2lkLCBvcHQyX2lkKSAlPiUKICBzdW1tYXJpc2UoCiAgICBwX3NyX29wdDEgPSBtZWFuKHBfc3Jfb3B0MSwgbmEucm0gPSBUUlVFKSwKICAgIC5ncm91cHMgPSAiZHJvcCIKICApCmBgYAoKYGBge3IgcGxvdC10aWVzfQpwbG90X3RpZXMgPC0gdGllX2l0ZW1fYW5hbHlzaXNfaHVtYW5zICU+JQogIGxlZnRfam9pbih0aWVfaXRlbV9hbmFseXNpc19iZnMpICU+JQogIGxlZnRfam9pbih0aWVfaXRlbV9hbmFseXNpc19zcikgJT4lCiAgbXV0YXRlKGl0ZW0gPSByb3dfbnVtYmVyKCksIGl0ZW0gPSBmYWN0b3IoaXRlbSkpICU+JQogIHBpdm90X2xvbmdlcigKICAgIHN0YXJ0c193aXRoKCJwXyIpLAogICAgbmFtZXNfdG8gPSAiYWdlbnQiLAogICAgdmFsdWVzX3RvID0gInBfY2hvb3NlX29wdDEiCiAgKSAlPiUKICBtdXRhdGUoCiAgICBhZ2VudCA9IHN0cl9yZW1vdmVfYWxsKGFnZW50LCAicF98X29wdDEiKSwKICAgIGFnZW50ID0gY2FzZV93aGVuKAogICAgICBhZ2VudCA9PSAiaHVtYW4iIH4gIkh1bWFuIiwKICAgICAgYWdlbnQgPT0gInNyIiB+ICJTUiIsCiAgICAgIGFnZW50ID09ICJiZnMiIH4gIkJGUyIsCiAgICApLAogICAgYWdlbnQgPSBmY3RfcmVsZXZlbChhZ2VudCwgIkh1bWFuIiwgIlNSIikKICApICU+JQogIGdncGxvdChhZXMoeD1zaG9ydGVzdF9wYXRoLCB5PXBfY2hvb3NlX29wdDEpKSArCiAgdGhlbWVfY3VzdG9tKCkgKwogIGZhY2V0X3dyYXAofmFnZW50KSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMC41LCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMjUpICsKICBzdGF0X3N1bW1hcnkoZ2VvbSA9ICJjcm9zc2JhciIsIGZ1biA9IG1lYW4sIGNvbG9yID0gInJlZCIpICsKICBzY2FsZV94X2Rpc2NyZXRlKG5hbWUgPSAiU2hvcnRlc3QgcGF0aCBkaXN0YW5jZSIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoCiAgICBuYW1lID0gInAoQ2hvb3NlIFNvdXJjZSBBID4gQikiLAogICAgbGFiZWxzID0gc2NhbGVzOjpwZXJjZW50LCBicmVha3MgPSBzZXEoMCwgMSwgMC4yNSkKICApICsKICB0aGVtZSgKICAgIHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCksCiAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIgogICkgKwogIGdndGl0bGUoIk5hdmlnYXRpb24gcHJvYmxlbXMgd2l0aCB0d28gY29ycmVjdCBhbnN3ZXJzIikKCnBsb3RfdGllcwoKaWYgKGtuaXR0aW5nKSB7CiAgZ2dzYXZlKAogICAgaGVyZSgiZmlndXJlcyIsIHN0cl9jKCJuYXZpZ2F0aW9uX2hlbGRvdXRfZGF5MSIsICIucGRmIikpLAogICAgcGxvdCA9IHBsb3RfdGllcywKICAgIHdpZHRoID0gOC8yLCBoZWlnaHQgPSAyLjUsCiAgICB1bml0cyA9ICJpbiIsIGRwaSA9IDMwMAogICkKfQpgYGAKCgojIERvZXMgbmF2aWdhdGlvbiBpbXByb3ZlIGFmdGVyIHJlc3Q/CgpGaXJzdCwgc29tZSBkZXNjcmlwdGl2ZXMuLi4KCmBgYHtyIGRlc2NyaXB0aXZlLW5hdmlnYXRpb24tYWxsfQpiaW5kX3Jvd3MobmF2X3N0dWR5MSwgbmF2X3N0dWR5MiwgbmF2X3N0dWR5MykgJT4lCiAgZ3JvdXBfYnkobWVhc3VyZW1lbnRfaWQsIHNob3J0ZXN0X3BhdGgpICU+JQogIHN1bW1hcmlzZShhY2N1cmFjeSA9IG1lYW4oY29ycmVjdCksIC5ncm91cHMgPSAiZHJvcCIpICU+JQogIGFycmFuZ2UobWVhc3VyZW1lbnRfaWQsIHNob3J0ZXN0X3BhdGgpICU+JQogIHBpdm90X3dpZGVyKAogICAgbmFtZXNfZnJvbSA9IHNob3J0ZXN0X3BhdGgsIHZhbHVlc19mcm9tID0gYWNjdXJhY3ksIG5hbWVzX3ByZWZpeCA9ICJkaXN0LSIKICApICU+JQogIGtibCgKICAgIGNhcHRpb24gPSBzdHJfYygKICAgICAgIjxjZW50ZXI+IiwgIkRlc2NyaXB0aXZlOiBOYXZpZ2F0aW9uIGFjY3VyYWN5IiwgIjwvY2VudGVyPiIKICAgICksCiAgICBkaWdpdHMgPSAyCiAgKSAlPiUKICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygicmVzcG9uc2l2ZSIpKQpgYGAKCiMjIE92ZXJuaWdodCByZXN0CgpOb3cgd2Ugd2FudCB0byBzZWUgaG93IG5hdmlnYXRpb24gYWNjdXJhY3kgY2hhbmdlcyBmcm9tIGRheSAxIHRvIGRheSAyLiBUaGlzIHBvb2xzIGFjcm9zcyBzdHVkaWVzIDItMyAoc3R1ZHkgMSB3YXMgb25seSBhIG9uZS1kYXkgZXhwZXJpbWVudCkuCgpgYGB7ciBzdGF0cy1kYXkxLXRvLWRheTJ9Cm5hdl9kYXkxX3RvX2RheTIgPC0gYmluZF9yb3dzKG5hdl9zdHVkeTIsIG5hdl9zdHVkeTMpICU+JQogIGZpbHRlcihtZWFzdXJlbWVudF9pZCAlaW4lIGMoIkQxIiwgIkQyIikpICU+JQogICMgR2l2ZSBldmVyeSBzdWJqZWN0IGEgZGlzdGluY3QgaWRlbnRpZmllcgogIG11dGF0ZShzdWJfaWQgPSBzdHJfYyhzdHVkeSwgIiBzIiwgc3ViX2lkKSkKCnN0YXRzX25hdl9kYXkyX2Rpc3QyIDwtIG5hdl9kYXkxX3RvX2RheTIgJT4lCiAgbXV0YXRlKHNob3J0ZXN0X3BhdGggPSBmY3RfcmVsZXZlbChzaG9ydGVzdF9wYXRoLCAiMiIpKSAlPiUKICBnbG1tVE1CKAogICAgY29ycmVjdCB+IHNob3J0ZXN0X3BhdGggKiBtZWFzdXJlbWVudF9pZCArCiAgICAgICgxICsgc2hvcnRlc3RfcGF0aCArIG1lYXN1cmVtZW50X2lkIHwgc3ViX2lkKSArICgxIHwgc3R1ZHkpLAogICAgZmFtaWx5ID0gYmlub21pYWwsCiAgICBkYXRhID0gLgogICkKCnN0YXRzX25hdl9kYXkyX2Rpc3QzIDwtIG5hdl9kYXkxX3RvX2RheTIgJT4lCiAgbXV0YXRlKHNob3J0ZXN0X3BhdGggPSBmY3RfcmVsZXZlbChzaG9ydGVzdF9wYXRoLCAiMyIpKSAlPiUKICBnbG1tVE1CKAogICAgY29ycmVjdCB+IHNob3J0ZXN0X3BhdGggKiBtZWFzdXJlbWVudF9pZCArCiAgICAgICgxICsgc2hvcnRlc3RfcGF0aCArIG1lYXN1cmVtZW50X2lkIHwgc3ViX2lkKSArICgxIHwgc3R1ZHkpLAogICAgZmFtaWx5ID0gYmlub21pYWwsCiAgICBkYXRhID0gLgogICkKCnN0YXRzX25hdl9kYXkyX2Rpc3Q0IDwtIG5hdl9kYXkxX3RvX2RheTIgJT4lCiAgbXV0YXRlKHNob3J0ZXN0X3BhdGggPSBmY3RfcmVsZXZlbChzaG9ydGVzdF9wYXRoLCAiNCIpKSAlPiUKICBnbG1tVE1CKAogICAgY29ycmVjdCB+IHNob3J0ZXN0X3BhdGggKiBtZWFzdXJlbWVudF9pZCArCiAgICAgICgxICsgc2hvcnRlc3RfcGF0aCArIG1lYXN1cmVtZW50X2lkIHwgc3ViX2lkKSArICgxIHwgc3R1ZHkpLAogICAgZmFtaWx5ID0gYmlub21pYWwsCiAgICBkYXRhID0gLgogICkKCm1hcF9kZnIoCiAgLnggPSBsaXN0KAogICAgImRpc3QtMiIgPSBzdGF0c19uYXZfZGF5Ml9kaXN0MiwKICAgICJkaXN0LTMiID0gc3RhdHNfbmF2X2RheTJfZGlzdDMsCiAgICAiZGlzdC00IiA9IHN0YXRzX25hdl9kYXkyX2Rpc3Q0CiAgKSwKICAuZiA9IH50aWR5KC54LCBjb25mLmludCA9IFRSVUUpLAogIC5pZCA9ICJyZWZfY2F0IgopICU+JQogIGNoZWNrX3NpZ25pZmljYW5jZSgpICU+JQogIHNlbGVjdCgtYyhyZWZfY2F0LCBlZmZlY3QsIGNvbXBvbmVudCkpICU+JQogIGtibCgKICAgIGNhcHRpb24gPSBzdHJfYygKICAgICAgIjxjZW50ZXI+IiwgIk5hdmlnYXRpb24gYWNjdXJhY3k6IERheSAxIHRvIERheSAyIiwgIjwvY2VudGVyPiIKICAgICksCiAgICBkaWdpdHMgPSAzCiAgKSAlPiUKICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygicmVzcG9uc2l2ZSIpKSAlPiUKICBwYWNrX3Jvd3MoIlJlZi4gQ2F0LiBkaXN0LTIiLCAxLCAxNykgJT4lCiAgcGFja19yb3dzKCJSZWYuIENhdC4gZGlzdC0zIiwgMTgsIDM0KSAlPiUKICBwYWNrX3Jvd3MoIlJlZi4gQ2F0LiBkaXN0LTQiLCAzNSwgNTEpCmBgYAoKYGBge3IgcGxvdC1kYXkxLXRvLWRheTJ9CnByZWRpY3RfbmF2X2RheTFfdG9fZGF5MiA8LSBleHBhbmRfZ3JpZCgKICBtZWFzdXJlbWVudF9pZCA9IGMoIkQxIiwgIkQyIiksCiAgc2hvcnRlc3RfcGF0aCA9IGZhY3RvcigyOjQpLAogIHN1Yl9pZCA9IE5BLCBzdHVkeSA9IE5BCikgJT4lCiAgcHJlZGljdF9nbG1tVE1CKHN0YXRzX25hdl9kYXkyX2Rpc3QyKQoKcGxvdF9uYXZfZGF5MV90b19kYXkyIDwtIG5hdl9kYXkxX3RvX2RheTIgJT4lCiAgZ3JvdXBfYnkoc3ViX2lkLCBtZWFzdXJlbWVudF9pZCwgc2hvcnRlc3RfcGF0aCkgJT4lCiAgc3VtbWFyaXNlKGFjY3VyYWN5ID0gbWVhbihjb3JyZWN0KSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lCiAgZ2dwbG90KGFlcyh4PXNob3J0ZXN0X3BhdGgsIHk9YWNjdXJhY3ksIGNvbG9yPW1lYXN1cmVtZW50X2lkKSkgKwogIHRoZW1lX2N1c3RvbSgpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLjUsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX2RvdHBsb3QoCiAgICBhZXMoZmlsbCA9IG1lYXN1cmVtZW50X2lkKSwKICAgIGJpbndpZHRoID0gMC4wMSwKICAgIGJpbmF4aXMgPSAieSIsIHN0YWNrZGlyID0gImNlbnRlciIsCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC43NSksCiAgICBkb3RzaXplID0gMSwgYWxwaGEgPSAwLjUsIGNvbG9yID0gTkEsCiAgICBzaG93LmxlZ2VuZCA9IEZBTFNFCiAgKSArCiAgZ2VvbV9wb2ludHJhbmdlKAogICAgYWVzKAogICAgICB4ID0gc2hvcnRlc3RfcGF0aCwgeSA9IGZpdCwKICAgICAgeW1pbiA9IGZpdCAtIHNlLmZpdCwgeW1heCA9IGZpdCArIHNlLmZpdCwKICAgICAgY29sb3IgPSBtZWFzdXJlbWVudF9pZAogICAgKSwKICAgIGRhdGEgPSBwcmVkaWN0X25hdl9kYXkxX3RvX2RheTIsIGluaGVyaXQuYWVzID0gRkFMU0UsIHNob3cubGVnZW5kID0gRkFMU0UsCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC4xNSksIGxpbmV3aWR0aCA9IDEKICApICsKICBnZW9tX2xpbmUoCiAgICBhZXMoCiAgICAgIHggPSBzaG9ydGVzdF9wYXRoLCB5ID0gZml0LAogICAgICBncm91cCA9IG1lYXN1cmVtZW50X2lkLCBjb2xvciA9IG1lYXN1cmVtZW50X2lkCiAgICApLAogICAgZGF0YSA9IHByZWRpY3RfbmF2X2RheTFfdG9fZGF5MiwgaW5oZXJpdC5hZXMgPSBGQUxTRSwKICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjE1KSwgbGluZXdpZHRoID0gMQogICkgKwogIHNjYWxlX3hfZGlzY3JldGUobmFtZSA9ICJTaG9ydGVzdCBwYXRoIGRpc3RhbmNlIikgKwogIHNjYWxlX3lfY29udGludW91cygKICAgIG5hbWUgPSAiQWNjdXJhY3kiLCBsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQsIGJyZWFrcyA9IHNlcSgwLCAxLCAwLjI1KQogICkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCgKICAgIG5hbWUgPSAiTWVhc3VyZW1lbnQiLAogICAgdmFsdWVzID0gYygiRDEiPSIjZmE5ZmI1IiwgIkQyIj0iIzdhMDE3NyIpLAogICAgbGFiZWxzID0gYygiRDEiPSJCZWZvcmUgb3Zlcm5pZ2h0IHJlc3QiLCAiRDIiPSJBZnRlciBvdmVybmlnaHQgcmVzdCIpCiAgKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiRDEiPSIjZmE5ZmI1IiwgIkQyIj0iIzdhMDE3NyIpKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKDAuMywgMS4xKSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgZ2d0aXRsZSgiTmF2aWdhdGlvbiBhZnRlciBvdmVybmlnaHQgcmVzdCIpCgpwbG90X25hdl9kYXkxX3RvX2RheTIKCmlmIChrbml0dGluZykgewogIGdnc2F2ZSgKICAgIGhlcmUoImZpZ3VyZXMiLCBzdHJfYygibmF2aWdhdGlvbl9kYXkxX3RvX2RheTIiLCAiLnBkZiIpKSwKICAgIHBsb3QgPSBwbG90X25hdl9kYXkxX3RvX2RheTIsCiAgICB3aWR0aCA9IDQsIGhlaWdodCA9IDMsCiAgICB1bml0cyA9ICJpbiIsIGRwaSA9IDMwMAogICkKfQpgYGAKCiMjIEF3YWtlIHJlc3QKCklzIGEgYnJpZWYgcGVyaW9kIG9mIGF3YWtlIHJlc3Qgc3VmZmljaWVudCBmb3IgaW1wcm92aW5nIG5hdmlnYXRpb24gYWNjdXJhY3k/CgpgYGB7ciBzdGF0cy1hd2FrZS1yZXN0fQpzdGF0c19uYXZfYXdha2VfZGlzdDIgPC0gbmF2X3N0dWR5MyAlPiUKICBmaWx0ZXIobWVhc3VyZW1lbnRfaWQgJWluJSBjKCJEMSIsICJEMWIiKSkgJT4lCiAgbXV0YXRlKHNob3J0ZXN0X3BhdGggPSBmY3RfcmVsZXZlbChzaG9ydGVzdF9wYXRoLCAiMiIpKSAlPiUKICBnbG1tVE1CKAogICAgY29ycmVjdCB+IHNob3J0ZXN0X3BhdGggKiBtZWFzdXJlbWVudF9pZCArCiAgICAgICgxICsgc2hvcnRlc3RfcGF0aCArIG1lYXN1cmVtZW50X2lkIHwgc3ViX2lkKSwKICAgIGZhbWlseSA9IGJpbm9taWFsLAogICAgZGF0YSA9IC4KICApCgpzdGF0c19uYXZfYXdha2VfZGlzdDMgPC0gbmF2X3N0dWR5MyAlPiUKICBmaWx0ZXIobWVhc3VyZW1lbnRfaWQgJWluJSBjKCJEMSIsICJEMWIiKSkgJT4lCiAgbXV0YXRlKHNob3J0ZXN0X3BhdGggPSBmY3RfcmVsZXZlbChzaG9ydGVzdF9wYXRoLCAiMyIpKSAlPiUKICBnbG1tVE1CKAogICAgY29ycmVjdCB+IHNob3J0ZXN0X3BhdGggKiBtZWFzdXJlbWVudF9pZCArCiAgICAgICgxICsgc2hvcnRlc3RfcGF0aCArIG1lYXN1cmVtZW50X2lkIHwgc3ViX2lkKSwKICAgIGZhbWlseSA9IGJpbm9taWFsLAogICAgZGF0YSA9IC4KICApCgpzdGF0c19uYXZfYXdha2VfZGlzdDQgPC0gbmF2X3N0dWR5MyAlPiUKICBmaWx0ZXIobWVhc3VyZW1lbnRfaWQgJWluJSBjKCJEMSIsICJEMWIiKSkgJT4lCiAgbXV0YXRlKHNob3J0ZXN0X3BhdGggPSBmY3RfcmVsZXZlbChzaG9ydGVzdF9wYXRoLCAiNCIpKSAlPiUKICBnbG1tVE1CKAogICAgY29ycmVjdCB+IHNob3J0ZXN0X3BhdGggKiBtZWFzdXJlbWVudF9pZCArCiAgICAgICgxICsgc2hvcnRlc3RfcGF0aCArIG1lYXN1cmVtZW50X2lkIHwgc3ViX2lkKSwKICAgIGZhbWlseSA9IGJpbm9taWFsLAogICAgZGF0YSA9IC4KICApCgptYXBfZGZyKAogIC54ID0gbGlzdCgKICAgICJkaXN0LTIiID0gc3RhdHNfbmF2X2F3YWtlX2Rpc3QyLAogICAgImRpc3QtMyIgPSBzdGF0c19uYXZfYXdha2VfZGlzdDMsCiAgICAiZGlzdC00IiA9IHN0YXRzX25hdl9hd2FrZV9kaXN0NAogICksCiAgLmYgPSB+dGlkeSgueCwgY29uZi5pbnQgPSBUUlVFKSwKICAuaWQgPSAicmVmX2NhdCIKKSAlPiUKICBjaGVja19zaWduaWZpY2FuY2UoKSAlPiUKICBzZWxlY3QoLWMocmVmX2NhdCwgZWZmZWN0LCBjb21wb25lbnQpKSAlPiUKICBrYmwoCiAgICBjYXB0aW9uID0gc3RyX2MoIjxjZW50ZXI+IiwgIk5hdmlnYXRpb24gYWNjdXJhY3k6IEF3YWtlIFJlc3QiLCAiPC9jZW50ZXI+IiksCiAgICBkaWdpdHMgPSAzCiAgKSAlPiUKICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygicmVzcG9uc2l2ZSIpKSAlPiUKICBwYWNrX3Jvd3MoIlJlZi4gQ2F0LiBkaXN0LTIiLCAxLCAxNikgJT4lCiAgcGFja19yb3dzKCJSZWYuIENhdC4gZGlzdC0zIiwgMTcsIDMyKSAlPiUKICBwYWNrX3Jvd3MoIlJlZi4gQ2F0LiBkaXN0LTQiLCAzMywgNDgpCmBgYAoKYGBge3IgcGxvdC1hd2FrZS1yZXN0fQpwcmVkaWN0X25hdl9hd2FrZSA8LSBleHBhbmRfZ3JpZCgKICBtZWFzdXJlbWVudF9pZCA9IGMoIkQxIiwgIkQxYiIpLAogIHNob3J0ZXN0X3BhdGggPSBmYWN0b3IoMjo0KSwKICBzdWJfaWQgPSBOQSwgc3R1ZHkgPSBOQQopICU+JQogIHByZWRpY3RfZ2xtbVRNQihzdGF0c19uYXZfYXdha2VfZGlzdDIpCgpwbG90X25hdl9hd2FrZSA8LSBuYXZfc3R1ZHkzICU+JQogIGZpbHRlcihtZWFzdXJlbWVudF9pZCAlaW4lIGMoIkQxIiwgIkQxYiIpKSAlPiUKICBncm91cF9ieShzdWJfaWQsIG1lYXN1cmVtZW50X2lkLCBzaG9ydGVzdF9wYXRoKSAlPiUKICBzdW1tYXJpc2UoYWNjdXJhY3kgPSBtZWFuKGNvcnJlY3QpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUKICBnZ3Bsb3QoYWVzKHg9c2hvcnRlc3RfcGF0aCwgeT1hY2N1cmFjeSwgY29sb3I9bWVhc3VyZW1lbnRfaWQpKSArCiAgdGhlbWVfY3VzdG9tKCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAuNSwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21fZG90cGxvdCgKICAgIGFlcyhmaWxsID0gbWVhc3VyZW1lbnRfaWQpLAogICAgYmlud2lkdGggPSAwLjAxLAogICAgYmluYXhpcyA9ICJ5Iiwgc3RhY2tkaXIgPSAiY2VudGVyIiwKICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjc1KSwKICAgIGRvdHNpemUgPSAxLCBhbHBoYSA9IDAuNSwgY29sb3IgPSBOQSwKICAgIHNob3cubGVnZW5kID0gRkFMU0UKICApICsKICBnZW9tX3BvaW50cmFuZ2UoCiAgICBhZXMoCiAgICAgIHggPSBzaG9ydGVzdF9wYXRoLCB5ID0gZml0LAogICAgICB5bWluID0gZml0IC0gc2UuZml0LCB5bWF4ID0gZml0ICsgc2UuZml0LAogICAgICBjb2xvciA9IG1lYXN1cmVtZW50X2lkCiAgICApLAogICAgZGF0YSA9IHByZWRpY3RfbmF2X2F3YWtlLCBpbmhlcml0LmFlcyA9IEZBTFNFLCBzaG93LmxlZ2VuZCA9IEZBTFNFLAogICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuMTUpLCBsaW5ld2lkdGggPSAxCiAgKSArCiAgZ2VvbV9saW5lKAogICAgYWVzKAogICAgICB4ID0gc2hvcnRlc3RfcGF0aCwgeSA9IGZpdCwKICAgICAgZ3JvdXAgPSBtZWFzdXJlbWVudF9pZCwgY29sb3IgPSBtZWFzdXJlbWVudF9pZAogICAgKSwKICAgIGRhdGEgPSBwcmVkaWN0X25hdl9hd2FrZSwgaW5oZXJpdC5hZXMgPSBGQUxTRSwKICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjE1KSwgbGluZXdpZHRoID0gMQogICkgKwogIHNjYWxlX3hfZGlzY3JldGUobmFtZSA9ICJTaG9ydGVzdCBwYXRoIGRpc3RhbmNlIikgKwogIHNjYWxlX3lfY29udGludW91cygKICAgIG5hbWUgPSAiQWNjdXJhY3kiLCBsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQsIGJyZWFrcyA9IHNlcSgwLCAxLCAwLjI1KQogICkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCgKICAgIG5hbWUgPSAiTWVhc3VyZW1lbnQiLAogICAgdmFsdWVzID0gYygiRDEiPSIjZmE5ZmI1IiwgIkQxYiI9IiMyYzdmYjgiKSwKICAgIGxhYmVscyA9IGMoIkQxIj0iQmVmb3JlIG92ZXJuaWdodCByZXN0IiwgIkQxYiI9IkFmdGVyIGF3YWtlIHJlc3QiKQogICkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIkQxIj0iI2ZhOWZiNSIsICJEMWIiPSIjMmM3ZmI4IikpICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMC4zLCAxLjEpKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICBnZ3RpdGxlKCJOYXZpZ2F0aW9uIGFmdGVyIGF3YWtlIHJlc3QiKQoKcGxvdF9uYXZfYXdha2UKCmlmIChrbml0dGluZykgewogIGdnc2F2ZSgKICAgIGhlcmUoImZpZ3VyZXMiLCBzdHJfYygibmF2aWdhdGlvbl9hd2FrZV9yZXN0IiwgIi5wZGYiKSksCiAgICBwbG90ID0gcGxvdF9uYXZfYXdha2UsCiAgICB3aWR0aCA9IDQsIGhlaWdodCA9IDMsCiAgICB1bml0cyA9ICJpbiIsIGRwaSA9IDMwMAogICkKfQpgYGAKCiMjIFNSIHJlcGxheSBzaW11bGF0aW9uCgpCZWZvcmUgc3RhcnRpbmcgdG8gZG8gYW55IHNpbXVsYXRpb24sIHdlIGZpcnN0IHdhbnQgdG8ga25vdyBob3cgbXVjaCByZXBsYXkgYW4gYWdlbnQgY2FuIGZpdCBpbnRvIGRpZmZlcmVudCBwZXJpb2RzIG9mIHRpbWUuIEJhc2VkIG9uIHBhc3QgcmVzZWFyY2ggbWVhc3VyaW5nIG5ldXJhbCByZXBsYXkgZXZlbnRzLCB3ZSdsbCBhc3N1bWUgdGhhdCBpdCB0YWtlcyBhYm91dCA1MG1zIGZvciB0aGUgYnJhaW4gdG8gcmVwbGF5IGEgc2luZ2xlIGl0ZW0gZnJvbSBhIHNlcXVlbmNlLiBUaGlzIHdpbGwgbGV0IHVzIGNhbGN1bGF0ZSB0aGUgdG90YWwgbnVtYmVyIG9mIGl0ZW1zIHRoYXQgY291bGQgYmUgcmVwbGF5ZWQgaW4gZWFjaCBlcG9jaC4gVG8gc2ltcGxpZnkgdGhlIHByb2Nlc3Mgb2YgYWN0dWFsbHkgcnVubmluZyB0aGUgc2ltdWxhdGlvbiwgd2UnbGwgY29udmVydCB0aGlzIHF1YW50aXR5IGludG8gdGhlIG51bWJlciBvZiAic2V0cyIgdGhhdCBjYW4gYmUgcmVwbGF5ZWQsIHdoZXJlIGEgc2luZ2xlICJzZXQiIGNvbnNpc3RzIG9mIHRoZSB0b3RhbCBudW1iZXIgb2YgcmVsYXRpb25zaGlwcyBpbiB0aGUgbmV0d29yayAoaS5lLiwgdGhlIG51bWJlciBvZiB1bmRpcmVjdGVkIGVkZ2VzID0gMTcsIG1lYW5pbmcgdGhhdCBlYWNoIHNldCBjb25zaXN0cyBvZiAzNCBvYnNlcnZhdGlvbnMgYmVjYXVzZSBlYWNoIHNldCBjb250YWlucyBvYnNlcnZhdGlvbnMgb2YgYm90aCBBLT5CIGFuZCBCLT5BKS4KCmBgYHtyIGF2YWlsLXNyLXJlcGxheS10aW1lfQp0aWJibGUobWludXRlc19mb3JfcmVwbGF5ID0gYygxLCA1LCAxNSwgMzAsIDYwLCAxMjApKSAlPiUKICBtdXRhdGUoCiAgICBuX2l0ZW1zID0gbWludXRlc19mb3JfcmVwbGF5IC8gKDAuMDUgLyA2MCksCiAgICBuX3NldHMgPSBuX2l0ZW1zIC8gMzQKICApICU+JQogIGtibCgKICAgIGNhcHRpb24gPSBzdHJfYygiPGNlbnRlcj4iLCAiU1IgcmVwbGF5IHRpbWUiLCAiPC9jZW50ZXI+IiksCiAgICBkaWdpdHMgPSAyCiAgKSAlPiUKICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygicmVzcG9uc2l2ZSIpKQpgYGAKCmBgYHtyIHNpbXVsYXRlLXNyLXJlcGxheX0Kc2ltX3JlcGxheV8wX21pbiA8LSBzaW11bGF0ZWRfcGFpcmVkX2Fzc29jaWF0ZXMgJT4lCiAgZmlsdGVyKHNldCA8PSA2KSAlPiUKICBzaW11bGF0ZV9zcigpICU+JQogIG11dGF0ZShyZXBsYXlfdGltZSA9IDApCgpzaW1fcmVwbGF5XzFfbWluIDwtIHNpbXVsYXRlZF9wYWlyZWRfYXNzb2NpYXRlcyAlPiUKICBmaWx0ZXIoc2V0IDw9IDM1ICsgNikgJT4lCiAgc2ltdWxhdGVfc3IoKSAlPiUKICBtdXRhdGUocmVwbGF5X3RpbWUgPSAxKQoKc2ltX3JlcGxheV81X21pbiA8LSBzaW11bGF0ZWRfcGFpcmVkX2Fzc29jaWF0ZXMgJT4lCiAgZmlsdGVyKHNldCA8PSAxNzYgKyA2KSAlPiUKICBzaW11bGF0ZV9zcigpICU+JQogIG11dGF0ZShyZXBsYXlfdGltZSA9IDUpCgpzaW1fcmVwbGF5XzYwX21pbiA8LSBzaW11bGF0ZWRfcGFpcmVkX2Fzc29jaWF0ZXMgJT4lCiAgZmlsdGVyKHNldCA8PSAyMTE3ICsgNikgJT4lCiAgc2ltdWxhdGVfc3IoKSAlPiUKICBtdXRhdGUocmVwbGF5X3RpbWUgPSA2MCkKYGBgCgpgYGB7ciBwbG90LXNyLXNpbS1yZXBsYXl9CnBsb3Rfc2ltX3NyX3JlcGxheSA8LSBiaW5kX3Jvd3MoCiAgam9pbl9zcih0cmlhbGxpc3RfbmF2X2xlYXJuZWQsIHNpbV9yZXBsYXlfMF9taW4pLAogIGpvaW5fc3IodHJpYWxsaXN0X25hdl9sZWFybmVkLCBzaW1fcmVwbGF5XzFfbWluKSwKICBqb2luX3NyKHRyaWFsbGlzdF9uYXZfbGVhcm5lZCwgc2ltX3JlcGxheV81X21pbiksCiAgam9pbl9zcih0cmlhbGxpc3RfbmF2X2xlYXJuZWQsIHNpbV9yZXBsYXlfNjBfbWluKQopICU+JQogICMgRmVlZCB2YWx1ZXMgdGhyb3VnaCBzb2Z0bWF4CiAgbXV0YXRlKGFjcm9zcyhjKG9wdDFfc3IsIG9wdDJfc3IpLCB+LnggKiAxMDApKSAlPiUKICBleHBhbmRfZ3JpZCh0ZW1wZXJhdHVyZSA9IDEpICU+JQogIHJvd3dpc2UoKSAlPiUKICBtdXRhdGUoCiAgICBwX2NvcnJlY3QgPSBzb2Z0bWF4KAogICAgICBvcHRpb25fdmFsdWVzID0gYyhvcHQxX3NyLCBvcHQyX3NyKSwKICAgICAgb3B0aW9uX2Nob3NlbiA9IGlmX2Vsc2UoY29ycmVjdF9jaG9pY2UgPT0gb3B0MV9pZCwgMSwgMiksCiAgICAgIHRlbXBlcmF0dXJlID0gdGVtcGVyYXR1cmUsCiAgICAgIHVzZV9pbnZlcnNlX3RlbXBlcmF0dXJlID0gVFJVRQogICAgKQogICkgJT4lCiAgdW5ncm91cCgpICU+JQogICMgRm9yIHBsb3R0aW5nCiAgbXV0YXRlKAogICAgZ2FtbWEgPSBmYWN0b3IoZ2FtbWEpLAogICAgdGVtcGVyYXR1cmUgPSBzdHJfcGFkKHRlbXBlcmF0dXJlLCB3aWR0aCA9IDIsIHNpZGUgPSAibGVmdCIpLAogICAgdGVtcGVyYXR1cmUgPSBzdHJfYyh1bmljb2RlX2dyZWVrWyJ0YXUiXSwgIiA9ICIsIHRlbXBlcmF0dXJlKSwKICAgIHJlcGxheV90aW1lID0gc3RyX3BhZChyZXBsYXlfdGltZSwgd2lkdGggPSAyLCBzaWRlID0gImxlZnQiKSwKICAgIHJlcGxheV90aW1lID0gY2FzZV93aGVuKAogICAgICBzdHJfZGV0ZWN0KHJlcGxheV90aW1lLCAiMSQiKSB+IHN0cl9jKHJlcGxheV90aW1lLCAiIG1pbnV0ZSBvZiByZXBsYXkiKSwKICAgICAgcmVwbGF5X3RpbWUgPT0gIiAwIiB+ICJObyByZXBsYXkiLAogICAgICBUUlVFIH4gc3RyX2MocmVwbGF5X3RpbWUsICIgbWludXRlcyBvZiByZXBsYXkiKQogICAgKSwKICAgIHJlcGxheV90aW1lID0gZmN0X3JlbGV2ZWwocmVwbGF5X3RpbWUsICJObyByZXBsYXkiKQogICkgJT4lCiAgZ3JvdXBfYnkocmVwbGF5X3RpbWUsIGdhbW1hLCB0ZW1wZXJhdHVyZSwgc2hvcnRlc3RfcGF0aCkgJT4lCiAgc3VtbWFyaXNlKHBfY29ycmVjdCA9IG1lYW4ocF9jb3JyZWN0KSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lCiAgIyBQbG90CiAgZ2dwbG90KGFlcyh4PXNob3J0ZXN0X3BhdGgsIHk9cF9jb3JyZWN0LCBjb2xvcj1nYW1tYSkpICsKICB0aGVtZV9jdXN0b20oKSArCiAgZmFjZXRfZ3JpZChjb2xzID0gdmFycyhyZXBsYXlfdGltZSksIHJvd3MgPSB2YXJzKHRlbXBlcmF0dXJlKSkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAuNSwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21fbGluZShhZXMoY29sb3IgPSBnYW1tYSwgZ3JvdXAgPSBnYW1tYSksIGxpbmV3aWR0aCA9IDAuOCkgKwogIHNjYWxlX3hfZGlzY3JldGUobmFtZSA9ICJTaG9ydGVzdCBwYXRoIGRpc3RhbmNlIikgKwogIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIkFjY3VyYWN5IiwgbGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KSArCiAgc2NhbGVfY29sb3JfdmlyaWRpc19kKAogICAgbmFtZSA9IHN0cl9jKHVuaWNvZGVfZ3JlZWtbImdhbW1hIl0sICIgPSAiKSwgb3B0aW9uID0gInR1cmJvIiwgZW5kID0gMC45CiAgKSArCiAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKGJ5cm93ID0gVFJVRSwgbnJvdyA9IDEpKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKDAuNSwgMSkpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKwogIGdndGl0bGUoIlNpbXVsYXRlZCBlZmZlY3RzIG9mIFNSIHJlcGxheSBvbiBuYXZpZ2F0aW9uIikKCnBsb3Rfc2ltX3NyX3JlcGxheQoKaWYgKGtuaXR0aW5nKSB7CiAgZ2dzYXZlKAogICAgaGVyZSgiZmlndXJlcyIsIHN0cl9jKCJzaW11bGF0ZWRfcmVwbGF5IiwgIi5wZGYiKSksCiAgICBwbG90ID0gcGxvdF9zaW1fc3JfcmVwbGF5LAogICAgd2lkdGggPSA3LCBoZWlnaHQgPSAyLjUsCiAgICB1bml0cyA9ICJpbiIsIGRwaSA9IDMwMCwKICAgIGRldmljZSA9IGNhaXJvX3BkZgogICkKfQpgYGAKCiMjIFBQQyBiZWZvcmUvYWZ0ZXIgcmVzdAoKYGBge3IgcGxvdC1wcGMtZGF5MS1kYXkyfQpwbG90X3BwY19kYXkxX3RvX2RheTIgPC0gcHBjX3NyX2JlaGF2aW9yICU+JQogIGZpbHRlcihzdHVkeSAlaW4lIGMoIlN0dWR5IDIiLCAiU3R1ZHkgMyIpKSAlPiUKICBtdXRhdGUoCiAgICBtZWFzdXJlbWVudF9pZCA9IGNhc2Vfd2hlbigKICAgICAgbWVhc3VyZW1lbnRfaWQgPT0gIkQxIiB+ICJCZWZvcmUgcmVzdCIsCiAgICAgIG1lYXN1cmVtZW50X2lkID09ICJEMiIgfiAiQWZ0ZXIgcmVzdCIKICAgICksCiAgICBtZWFzdXJlbWVudF9pZCA9IGZjdF9yZWxldmVsKG1lYXN1cmVtZW50X2lkLCAiQmVmb3JlIHJlc3QiKQogICkgJT4lCiAgcGl2b3RfbG9uZ2VyKGMoZW1waXJpY2FsLCBwcmVkaWN0ZWQpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9c2hvcnRlc3RfcGF0aCwgeT12YWx1ZSkpICsKICB0aGVtZV9jdXN0b20oKSArCiAgZmFjZXRfd3JhcCh+bWVhc3VyZW1lbnRfaWQpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLjUsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX3BvaW50KAogICAgYWVzKGNvbG9yID0gbmFtZSksCiAgICBhbHBoYSA9IDAuMDUsCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcmRvZGdlKAogICAgICBqaXR0ZXIud2lkdGggPSAwLjIsIGppdHRlci5oZWlnaHQgPSAwLCBkb2RnZS53aWR0aCA9IDAuNSwgc2VlZCA9IDEKICAgICksCiAgICBzaG93LmxlZ2VuZCA9IEZBTFNFCiAgKSArCiAgc3RhdF9zdW1tYXJ5KAogICAgYWVzKGNvbG9yID0gbmFtZSksIGdlb20gPSAiY3Jvc3NiYXIiLCBmdW4gPSBtZWFuLAogICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjUpCiAgKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShuYW1lID0gIlNob3J0ZXN0IHBhdGggZGlzdGFuY2UiKSArCiAgc2NhbGVfeV9jb250aW51b3VzKAogICAgbmFtZSA9ICJBY2N1cmFjeSIsIGxhYmVscyA9IHNjYWxlczo6cGVyY2VudCwgYnJlYWtzID0gc2VxKDAsIDEsIDAuMjUpCiAgKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKAogICAgbmFtZSA9IE5VTEwsCiAgICB2YWx1ZXMgPSBjKCJlbXBpcmljYWwiPSIjZmQ4ZDNjIiwgInByZWRpY3RlZCI9IiNiZDAwMjYiKSwKICAgIGxhYmVscyA9IGMoImVtcGlyaWNhbCI9Ikh1bWFuIiwgInByZWRpY3RlZCI9IlNSIikKICApICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKwogIGdndGl0bGUoIlBvc3RlcmlvciBwcmVkaWN0aXZlIGNoZWNrIikKCnBsb3RfcHBjX2RheTFfdG9fZGF5MgoKaWYgKGtuaXR0aW5nKSB7CiAgZ2dzYXZlKAogICAgaGVyZSgiZmlndXJlcyIsIHN0cl9jKCJwcGNfZGF5MiIsICIucGRmIikpLAogICAgcGxvdCA9IHBsb3RfcHBjX2RheTFfdG9fZGF5MiwKICAgIHdpZHRoID0gOC8zLCBoZWlnaHQgPSAyLjUsCiAgICB1bml0cyA9ICJpbiIsIGRwaSA9IDMwMAogICkKfQpgYGAKCgojIyBSZWxhdGluZyBtb2RlbCBwYXJhbWV0ZXJzIHRvIG5hdmlnYXRpb24KCkRvZXMgZXN0aW1hdGVkIGdhbW1hIHNpZ25pZmljYW50bHkgaW5jcmVhc2UgYWZ0ZXIgb3Zlcm5pZ2h0IHJlc3Q/CgpgYGB7ciBzdGF0cy1nYW1tYS1pbmNyZWFzZX0KcGFyYW1zICU+JQogIGZpbHRlcigKICAgIHN0dWR5ICVpbiUgYygiU3R1ZHkgMiIsICJTdHVkeSAzIiksCiAgICBtZWFzdXJlbWVudF9pZCAlaW4lIGMoIkQxIiwgIkQyIiksCiAgICBtb2RlbCA9PSAic3IiLAogICAgcGFyYW1fbmFtZSA9PSAic3JfZ2FtbWEiCiAgKSAlPiUKICBzZWxlY3Qoc3R1ZHksIHN1Yl9pZCwgbWVhc3VyZW1lbnRfaWQsIHNyX2dhbW1hID0gcGFyYW1fdmFsdWUpICU+JQogIGdyb3VwX2J5KG1lYXN1cmVtZW50X2lkKSAlPiUKICBzdW1tYXJpc2UobWVkaWFuX2dhbW1hID0gbWVkaWFuKHNyX2dhbW1hKSkgJT4lCiAga2JsKAogICAgY2FwdGlvbiA9IHN0cl9jKAogICAgICAiPGNlbnRlcj4iLCAiTWVkaWFuIFNSIGdhbW1hIGJlZm9yZS9hZnRlciBvdmVybmlnaHQgcmVzdCIsICI8L2NlbnRlcj4iCiAgICApLAogICAgZGlnaXRzID0gMwogICkgJT4lCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInJlc3BvbnNpdmUiKSkKCnBhcmFtcyAlPiUKICBmaWx0ZXIoCiAgICBzdHVkeSAlaW4lIGMoIlN0dWR5IDIiLCAiU3R1ZHkgMyIpLAogICAgbWVhc3VyZW1lbnRfaWQgJWluJSBjKCJEMSIsICJEMiIpLAogICAgbW9kZWwgPT0gInNyIiwKICAgIHBhcmFtX25hbWUgPT0gInNyX2dhbW1hIgogICkgJT4lCiAgc2VsZWN0KHN0dWR5LCBzdWJfaWQsIG1lYXN1cmVtZW50X2lkLCBzcl9nYW1tYSA9IHBhcmFtX3ZhbHVlKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gbWVhc3VyZW1lbnRfaWQsIHZhbHVlc19mcm9tID0gc3JfZ2FtbWEpICU+JQogIHdpdGgoCiAgICB3aWxjb3gudGVzdCgKICAgICAgRDIsIEQxLCBhbHRlcm5hdGl2ZSA9ICJncmVhdGVyIiwgcGFpcmVkID0gVFJVRSwgY29uZi5pbnQgPSBUUlVFCiAgICApCiAgKSAlPiUKICB0aWR5KCkgJT4lCiAga2JsKAogICAgY2FwdGlvbiA9IHN0cl9jKAogICAgICAiPGNlbnRlcj4iLCAiSW5jcmVhc2UgaW4gU1IgZ2FtbWEgYWZ0ZXIgb3Zlcm5pZ2h0IHJlc3QiLCAiPC9jZW50ZXI+IgogICAgKSwKICAgIGRpZ2l0cyA9IDMKICApICU+JQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJyZXNwb25zaXZlIikpCmBgYAoKYGBge3IgcGxvdC1nYW1tYS1pbmNyZWFzZX0KcGxvdF9nYW1tYV9jaGFuZ2UgPC0gcGFyYW1zICU+JQogIGZpbHRlcigKICAgIHN0dWR5ICVpbiUgYygiU3R1ZHkgMiIsICJTdHVkeSAzIiksCiAgICBtZWFzdXJlbWVudF9pZCAlaW4lIGMoIkQxIiwgIkQyIiksCiAgICBtb2RlbCA9PSAic3IiLAogICAgcGFyYW1fbmFtZSA9PSAic3JfZ2FtbWEiCiAgKSAlPiUKICBzZWxlY3Qoc3R1ZHksIHN1Yl9pZCwgbWVhc3VyZW1lbnRfaWQsIHNyX2dhbW1hID0gcGFyYW1fdmFsdWUpICU+JQogIGdncGxvdChhZXMoeD1tZWFzdXJlbWVudF9pZCwgeT1zcl9nYW1tYSwgY29sb3I9bWVhc3VyZW1lbnRfaWQpKSArCiAgdGhlbWVfY3VzdG9tKCkgKwogIGdlb21fcG9pbnQoCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2ppdHRlcmRvZGdlKAogICAgICBqaXR0ZXIud2lkdGggPSAwLjI1LCBqaXR0ZXIuaGVpZ2h0ID0gMCwgZG9kZ2Uud2lkdGggPSAwLjUsIHNlZWQgPSAxCiAgICApLAogICAgYWxwaGEgPSAwLjI1LAogICAgc2hvdy5sZWdlbmQgPSBGQUxTRQogICkgKwogIHN0YXRfc3VtbWFyeSgKICAgIGdlb20gPSAiY3Jvc3NiYXIiLCBmdW4gPSBtZWRpYW4sIHBvc2l0aW9uID0gImRvZGdlIiwgc2hvdy5sZWdlbmQgPSBGQUxTRQogICkgKwogIHNjYWxlX3hfZGlzY3JldGUoCiAgICBuYW1lID0gIk1lYXN1cmVtZW50IiwKICAgIGxhYmVscyA9IGMoIkQxIj0iQmVmb3JlIHJlc3QiLCAiRDIiPSJBZnRlciByZXN0IikKICApICsKICBzY2FsZV95X2NvbnRpbnVvdXMoCiAgICBuYW1lID0gc3RyX2MoIkVzdGltYXRlZCAiLCB1bmljb2RlX2dyZWVrWyJnYW1tYSJdKSwKICAgIGJyZWFrcyA9IHNlcSgwLCAxLCAwLjI1KQogICkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCgKICAgIG5hbWUgPSAiTWVhc3VyZW1lbnQiLAogICAgdmFsdWVzID0gYygiRDEiPSIjZmE5ZmI1IiwgIkQyIj0iIzdhMDE3NyIpLAogICAgbGFiZWxzID0gYygiRDEiPSJCZWZvcmUgcmVzdCIsICJEMiI9IkFmdGVyIHJlc3QiKQogICkgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLCAxLjEpKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICBnZ3RpdGxlKAogICAgc3RyX2MoCiAgICAgIHVuaWNvZGVfZ3JlZWtbIkRlbHRhIl0sIHVuaWNvZGVfZ3JlZWtbImdhbW1hIl0sICIgYWZ0ZXIgb3Zlcm5pZ2h0IHJlc3QiCiAgICApCiAgKQoKcGxvdF9nYW1tYV9jaGFuZ2UKCmlmIChrbml0dGluZykgewogIGdnc2F2ZSgKICAgIGhlcmUoImZpZ3VyZXMiLCBzdHJfYygiZ2FtbWFfY2hhbmdlIiwgIi5wZGYiKSksCiAgICBwbG90ID0gcGxvdF9nYW1tYV9jaGFuZ2UsCiAgICB3aWR0aCA9IDgvMywgaGVpZ2h0ID0gMi41LAogICAgdW5pdHMgPSAiaW4iLCBkcGkgPSAzMDAsCiAgICBkZXZpY2UgPSBjYWlyb19wZGYKICApCn0KYGBgCgpBcmUgY2hhbmdlcyBpbiBlc3RpbWF0ZWQgZ2FtbWEgcmVsYXRlZCB0byBjaGFuZ2VzIGluIG5hdmlnYXRpb24gYmVoYXZpb3JzPwoKYGBge3Igc3RhdHMtZ2FtbWEtYWNjdXJhY3l9CmJpbmRfcm93cyhuYXZfc3R1ZHkyLCBuYXZfc3R1ZHkzKSAlPiUKICBmaWx0ZXIobWVhc3VyZW1lbnRfaWQgJWluJSBjKCJEMSIsICJEMiIpKSAlPiUKICBncm91cF9ieShzdHVkeSwgc3ViX2lkLCBtZWFzdXJlbWVudF9pZCwgc2hvcnRlc3RfcGF0aCkgJT4lCiAgc3VtbWFyaXNlKGFjY3VyYWN5ID0gbWVhbihjb3JyZWN0KSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IG1lYXN1cmVtZW50X2lkLCB2YWx1ZXNfZnJvbSA9IGFjY3VyYWN5KSAlPiUKICBtdXRhdGUoZGVsdGFfYWNjdXJhY3kgPSBEMiAtIEQxKSAlPiUKICBzZWxlY3QoLWMoRDEsIEQyKSkgJT4lCiAgIyAKICBsZWZ0X2pvaW4oCiAgICBwYXJhbXMgJT4lCiAgICAgIGZpbHRlcigKICAgICAgICBzdHVkeSAlaW4lIGMoIlN0dWR5IDIiLCAiU3R1ZHkgMyIpLAogICAgICAgIG1lYXN1cmVtZW50X2lkICVpbiUgYygiRDEiLCAiRDIiKSwKICAgICAgICBtb2RlbCA9PSAic3IiLAogICAgICAgIHBhcmFtX25hbWUgPT0gInNyX2dhbW1hIgogICAgICApICU+JQogICAgICBzZWxlY3Qoc3R1ZHksIHN1Yl9pZCwgbWVhc3VyZW1lbnRfaWQsIHNyX2dhbW1hID0gcGFyYW1fdmFsdWUpICU+JQogICAgICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gbWVhc3VyZW1lbnRfaWQsIHZhbHVlc19mcm9tID0gc3JfZ2FtbWEpICU+JQogICAgICBtdXRhdGUoZGVsdGFfc3IgPSBEMiAtIEQxKSAlPiUKICAgICAgc2VsZWN0KC1jKEQxLCBEMikpLAogICAgYnkgPSBjKCJzdHVkeSIsICJzdWJfaWQiKQogICkgJT4lCiAgZ3JvdXBfYnkoc2hvcnRlc3RfcGF0aCkgJT4lCiAgbmVzdCgpICU+JQogIG11dGF0ZSgKICAgIHRlc3QgPSBtYXAoCiAgICAgIC54ID0gZGF0YSwKICAgICAgLmYgPSB+d2l0aCgKICAgICAgICAueCwKICAgICAgICBjb3IudGVzdCgKICAgICAgICAgIGRlbHRhX2FjY3VyYWN5LCBkZWx0YV9zciwKICAgICAgICAgIG1ldGhvZCA9ICJzcGVhcm1hbiIsIGV4YWN0ID0gRkFMU0UsIGFsdGVybmF0aXZlID0gImdyZWF0ZXIiCiAgICAgICAgKQogICAgICApICU+JSB0aWR5KCkKICAgICkKICApICU+JQogIHVubmVzdCh0ZXN0KSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgc2VsZWN0KC1kYXRhKSAlPiUKICBrYmwoCiAgICBjYXB0aW9uID0gc3RyX2MoCiAgICAgICI8Y2VudGVyPiIsICLiiIYgQWNjdXJhY3kgfiDiiIYgU1IgZ2FtbWEgKGFmdGVyIG92ZXJuaWdodCByZXN0KSIsICI8L2NlbnRlcj4iCiAgICApLAogICAgZGlnaXRzID0gMwogICkgJT4lCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInJlc3BvbnNpdmUiKSkKYGBgCgpgYGB7ciBwbG90LWdhbW1hLWFjY3VyYWN5fQpwbG90X2dhbW1hX2FjY3VyYWN5X2NoYW5nZSA8LSBiaW5kX3Jvd3MobmF2X3N0dWR5MiwgbmF2X3N0dWR5MykgJT4lCiAgZmlsdGVyKG1lYXN1cmVtZW50X2lkICVpbiUgYygiRDEiLCAiRDIiKSkgJT4lCiAgZ3JvdXBfYnkoc3R1ZHksIHN1Yl9pZCwgbWVhc3VyZW1lbnRfaWQsIHNob3J0ZXN0X3BhdGgpICU+JQogIHN1bW1hcmlzZShhY2N1cmFjeSA9IG1lYW4oY29ycmVjdCksIC5ncm91cHMgPSAiZHJvcCIpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBtZWFzdXJlbWVudF9pZCwgdmFsdWVzX2Zyb20gPSBhY2N1cmFjeSkgJT4lCiAgbXV0YXRlKGRlbHRhX2FjY3VyYWN5ID0gRDIgLSBEMSkgJT4lCiAgc2VsZWN0KC1jKEQxLCBEMikpICU+JQogICMgCiAgbGVmdF9qb2luKAogICAgcGFyYW1zICU+JQogICAgICBmaWx0ZXIoCiAgICAgICAgc3R1ZHkgJWluJSBjKCJTdHVkeSAyIiwgIlN0dWR5IDMiKSwKICAgICAgICBtZWFzdXJlbWVudF9pZCAlaW4lIGMoIkQxIiwgIkQyIiksCiAgICAgICAgbW9kZWwgPT0gInNyIiwKICAgICAgICBwYXJhbV9uYW1lID09ICJzcl9nYW1tYSIKICAgICAgKSAlPiUKICAgICAgc2VsZWN0KHN0dWR5LCBzdWJfaWQsIG1lYXN1cmVtZW50X2lkLCBzcl9nYW1tYSA9IHBhcmFtX3ZhbHVlKSAlPiUKICAgICAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IG1lYXN1cmVtZW50X2lkLCB2YWx1ZXNfZnJvbSA9IHNyX2dhbW1hKSAlPiUKICAgICAgbXV0YXRlKGRlbHRhX3NyID0gRDIgLSBEMSkgJT4lCiAgICAgIHNlbGVjdCgtYyhEMSwgRDIpKSwKICAgIGJ5ID0gYygic3R1ZHkiLCAic3ViX2lkIikKICApICU+JQogIGdncGxvdChhZXMoeD1kZWx0YV9zciwgeT1kZWx0YV9hY2N1cmFjeSwgY29sb3I9c2hvcnRlc3RfcGF0aCkpICsKICB0aGVtZV9jdXN0b20oKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIpICsKICBnZW9tX3BvaW50KGFscGhhID0gMC4yNSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGxpbmV3aWR0aCA9IDEuNSkgKwogIHNjYWxlX3hfY29udGludW91cyhuYW1lID0gc3RyX2MoIkNoYW5nZSBpbiAiLCB1bmljb2RlX2dyZWVrWyJnYW1tYSJdKSkgKwogIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIkNoYW5nZSBpbiBhY2N1cmFjeSIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwoCiAgICBuYW1lID0gIlNob3J0ZXN0IHBhdGggZGlzdGFuY2UiLAogICAgdmFsdWVzID0gYygiIzg4Q0NFRSIsICIjQ0M2Njc3IiwgIiNERENDNzciKQogICkgKwogIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygtMSwgMS4xKSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgZ2d0aXRsZSgKICAgIHN0cl9jKAogICAgICB1bmljb2RlX2dyZWVrWyJEZWx0YSJdLCAiTmF2aWdhdGlvbiB+ICIsCiAgICAgIHVuaWNvZGVfZ3JlZWtbIkRlbHRhIl0sIHVuaWNvZGVfZ3JlZWtbImdhbW1hIl0KICAgICkKICApCgpwbG90X2dhbW1hX2FjY3VyYWN5X2NoYW5nZQoKaWYgKGtuaXR0aW5nKSB7CiAgc3VwcHJlc3NXYXJuaW5ncygKICAgIGdnc2F2ZSgKICAgICAgaGVyZSgiZmlndXJlcyIsIHN0cl9jKCJnYW1tYV9hY2N1cmFjeV9jaGFuZ2UiLCAiLnBkZiIpKSwKICAgICAgcGxvdCA9IHBsb3RfZ2FtbWFfYWNjdXJhY3lfY2hhbmdlLAogICAgICB3aWR0aCA9IDgvMywgaGVpZ2h0ID0gMi41LAogICAgICB1bml0cyA9ICJpbiIsIGRwaSA9IDMwMAogICAgKQogICkKICAKICBnZ3NhdmUoCiAgICBoZXJlKCJmaWd1cmVzIiwgc3RyX2MoImdhbW1hX2FjY3VyYWN5X2NoYW5nZV9jYWlybyIsICIucGRmIikpLAogICAgcGxvdCA9IHBsb3RfZ2FtbWFfYWNjdXJhY3lfY2hhbmdlLAogICAgd2lkdGggPSA4LzMsIGhlaWdodCA9IDIuNSwKICAgIHVuaXRzID0gImluIiwgZHBpID0gMzAwLAogICAgZGV2aWNlID0gY2Fpcm9fcGRmCiAgKQp9CmBgYAoKCiMgRXZpZGVuY2Ugb2YgY2FjaGVkIHJlcHJlc2VudGF0aW9uCgpIZXJlLCB3ZSdyZSB0cnlpbmcgdG8gZ2V0IGEgc2Vuc2UgZm9yIHdoYXQgaXMgYmVpbmcgY2FjaGVkLCBhbmQgdHJ5aW5nIHRvIHNlZSBpZiB0aGVyZSdzIGV2aWRlbmNlIHRoYXQgY2FjaGluZyAoYXMgb3Bwb3NlZCB0byBtb2RlbC1iYXNlZCBwbGFubmluZykgaXMgdGhlIHByaW1hcnkgZHJpdmVyIG9mIG5hdmlnYXRpb24gaW1wcm92ZW1lbnQgYWZ0ZXIgb3Zlcm5pZ2h0IHJlc3QuCgojIyBTaW11bGF0aW9uIHZpc3VhbGl6YXRpb24KCmBgYHtyIHBsb3QtbmV0d29yay13aXRoLXNyfQpidXR0ZXJmbHlfbGF5b3V0IDwtIGNyZWF0ZV9sYXlvdXQoZywgbGF5b3V0ID0gInN0cmVzcyIpCgpwbG90X25ldHdvcmtfd2l0aF9zciA8LSBzaW1fc3JfbWF0cml4X2FzeW1wdG90aWMgJT4lCiAgbXV0YXRlKAogICAgZnJvbV9zb3J0ZWQgPSBpZl9lbHNlKGZyb20gPCB0bywgZnJvbSwgdG8pLAogICAgdG9fc29ydGVkID0gaWZfZWxzZShmcm9tIDwgdG8sIHRvLCBmcm9tKQogICkgJT4lCiAgZ3JvdXBfYnkoZ2FtbWEsIGZyb20gPSBmcm9tX3NvcnRlZCwgdG8gPSB0b19zb3J0ZWQpICU+JQogIHN1bW1hcmlzZShzcl92YWx1ZSA9IG1lYW4oc3JfdmFsdWUpKSAlPiUKICBmaWx0ZXIocm91bmQoZ2FtbWEsIDEpICVpbiUgYygwLjEsIDAuNSwgMC45KSkgJT4lCiAgZmlsdGVyKHNyX3ZhbHVlID4gMC4wNSkgJT4lCiAgbGVmdF9qb2luKGFkamxpc3QpICU+JQogIGZpbHRlcihmcm9tIDwgdG8pICU+JQogIG11dGF0ZSgKICAgIGVkZ2UgPSBmYWN0b3IoZWRnZSksCiAgICBnYW1tYSA9IHN0cl9jKHVuaWNvZGVfZ3JlZWtbImdhbW1hIl0sICIgPSAiLCBnYW1tYSkKICApICU+JQogIHRibF9ncmFwaChlZGdlcyA9IC4sIGRpcmVjdGVkID0gRkFMU0UpICU+JQogIG11dGF0ZShuYW1lID0gcm93X251bWJlcigpKSAlPiUKICBnZ3JhcGgoIm1hbnVhbCIsIHg9YnV0dGVyZmx5X2xheW91dCR4LCB5PWJ1dHRlcmZseV9sYXlvdXQkeSkgKwogIHRoZW1lX25ldHdvcmsoKSArCiAgZmFjZXRfZWRnZXMofmdhbW1hLCBuY29sID0gMSkgKwogIGdlb21fZWRnZV9saW5rKGFlcyhhbHBoYSA9IHNyX3ZhbHVlLCBjb2xvciA9IGVkZ2UpKSArCiAgZ2VvbV9ub2RlX2xhYmVsKGFlcyhsYWJlbCA9IG5hbWUpKSArCiAgc2NhbGVfZWRnZV9jb2xvcl9tYW51YWwoCiAgICBuYW1lID0gTlVMTCwKICAgIHZhbHVlcyA9IGMoIjAiPSJyZWQiLCAiMSI9ImJsYWNrIiksCiAgICBsYWJlbHMgPSBjKCIwIj0iSW5mZXJyZWQgY29ubmVjdGlvbnMiLCAiMSI9Ik9ic2VydmVkIGNvbm5lY3Rpb25zIikKICApICsKICBzY2FsZV9lZGdlX2FscGhhKG5hbWUgPSAicChUYXJnZXQgfCBTb3VyY2UpIikgKwogIHRoZW1lKAogICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICBsZWdlbmQuYm94ID0gInZlcnRpY2FsIiwKICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMykKICApICsKICBnZ3RpdGxlKCJDb2duaXRpdmUgbWFwcyBwcmVkaWN0ZWQgYnkgU1IiKQoKcGxvdF9uZXR3b3JrX3dpdGhfc3IKCmlmIChrbml0dGluZykgewogIHN1cHByZXNzV2FybmluZ3MoCiAgICBnZ3NhdmUoCiAgICAgIGhlcmUoImZpZ3VyZXMiLCBzdHJfYygibmV0d29ya193aXRoX3NyIiwgIi5wZGYiKSksCiAgICAgIHBsb3QgPSBwbG90X25ldHdvcmtfd2l0aF9zciwKICAgICAgd2lkdGggPSAzLjUsIGhlaWdodCA9IDYsCiAgICAgIHVuaXRzID0gImluIiwgZHBpID0gMzAwCiAgICApCiAgKQogIAogIGdnc2F2ZSgKICAgIGhlcmUoImZpZ3VyZXMiLCBzdHJfYygibmV0d29ya193aXRoX3NyX2NhaXJvIiwgIi5wZGYiKSksCiAgICBwbG90ID0gcGxvdF9uZXR3b3JrX3dpdGhfc3IsCiAgICB3aWR0aCA9IDMuNSwgaGVpZ2h0ID0gNiwKICAgIHVuaXRzID0gImluIiwgZHBpID0gMzAwLAogICAgZGV2aWNlID0gY2Fpcm9fcGRmCiAgKQp9CmBgYAoKIyMgVHJhbnNpdGlvbiByZWV2YWx1YXRpb24KCkZvbGxvd2luZyB0cmFuc2l0aW9uIHJlZXZhbHVhdGlvbiwgYSBjYWNoaW5nIGFjY291bnQgcHJlZGljdHMgdGhhdCBwZW9wbGUncyBuYXZpZ2F0aW9uIHNob3VsZCBnZXQgd29yc2UgcmVsYXRpdmUgdG8gdGhlaXIgcGVyZm9ybWFuY2UgYWZ0ZXIgb3Zlcm5pZ2h0IHJlc3QuIEluIGNvbnRyYXN0LCBhIHBsYW5uaW5nIGFjY291bnQgcHJlZGljdHMgdGhhdCBwZW9wbGUncyBuYXZpZ2F0aW9uIHNob3VsZCBub3QgYmUgZ3JlYXRseSBpbXBhY3RlZCBieSBhIHJlbGF0aXZlbHkgc21hbGwgc2V0IG9mIGNoYW5nZXMuCgpgYGB7ciBzdGF0cy1yZWV2YWx1YXRpb259CnN0YXRzX25hdl90cl9kaXN0MiA8LSBiaW5kX3Jvd3MobmF2X3N0dWR5MiwgbmF2X3N0dWR5MykgJT4lCiAgZmlsdGVyKG1lYXN1cmVtZW50X2lkICVpbiUgYygiRDEiLCAiRDIiLCAiRDJiIikpICU+JQogIG11dGF0ZSgKICAgIG1lYXN1cmVtZW50X2lkID0gZmN0X3JlbGV2ZWwobWVhc3VyZW1lbnRfaWQsICJEMmIiKSwKICAgIHNob3J0ZXN0X3BhdGggPSBmY3RfcmVsZXZlbChzaG9ydGVzdF9wYXRoLCAiMiIpCiAgKSAlPiUKICBnbG1tVE1CKAogICAgY29ycmVjdCB+IHNob3J0ZXN0X3BhdGggKiBtZWFzdXJlbWVudF9pZCArCiAgICAgICgxICsgc2hvcnRlc3RfcGF0aCArIG1lYXN1cmVtZW50X2lkIHwgc3ViX2lkKSArICgxIHwgc3R1ZHkpLAogICAgZmFtaWx5ID0gYmlub21pYWwsCiAgICBkYXRhID0gLgogICkKCnN0YXRzX25hdl90cl9kaXN0MyA8LSBiaW5kX3Jvd3MobmF2X3N0dWR5MiwgbmF2X3N0dWR5MykgJT4lCiAgZmlsdGVyKG1lYXN1cmVtZW50X2lkICVpbiUgYygiRDEiLCAiRDIiLCAiRDJiIikpICU+JQogIG11dGF0ZSgKICAgIG1lYXN1cmVtZW50X2lkID0gZmN0X3JlbGV2ZWwobWVhc3VyZW1lbnRfaWQsICJEMmIiKSwKICAgIHNob3J0ZXN0X3BhdGggPSBmY3RfcmVsZXZlbChzaG9ydGVzdF9wYXRoLCAiMyIpCiAgKSAlPiUKICBnbG1tVE1CKAogICAgY29ycmVjdCB+IHNob3J0ZXN0X3BhdGggKiBtZWFzdXJlbWVudF9pZCArCiAgICAgICgxICsgc2hvcnRlc3RfcGF0aCArIG1lYXN1cmVtZW50X2lkIHwgc3ViX2lkKSArICgxIHwgc3R1ZHkpLAogICAgZmFtaWx5ID0gYmlub21pYWwsCiAgICBkYXRhID0gLgogICkKCnN0YXRzX25hdl90cl9kaXN0NCA8LSBiaW5kX3Jvd3MobmF2X3N0dWR5MiwgbmF2X3N0dWR5MykgJT4lCiAgZmlsdGVyKG1lYXN1cmVtZW50X2lkICVpbiUgYygiRDEiLCAiRDIiLCAiRDJiIikpICU+JQogIG11dGF0ZSgKICAgIG1lYXN1cmVtZW50X2lkID0gZmN0X3JlbGV2ZWwobWVhc3VyZW1lbnRfaWQsICJEMmIiKSwKICAgIHNob3J0ZXN0X3BhdGggPSBmY3RfcmVsZXZlbChzaG9ydGVzdF9wYXRoLCAiNCIpCiAgKSAlPiUKICBnbG1tVE1CKAogICAgY29ycmVjdCB+IHNob3J0ZXN0X3BhdGggKiBtZWFzdXJlbWVudF9pZCArCiAgICAgICgxICsgc2hvcnRlc3RfcGF0aCArIG1lYXN1cmVtZW50X2lkIHwgc3ViX2lkKSArICgxIHwgc3R1ZHkpLAogICAgZmFtaWx5ID0gYmlub21pYWwsCiAgICBkYXRhID0gLgogICkKCm1hcF9kZnIoCiAgLnggPSBsaXN0KAogICAgImRpc3QtMiIgPSBzdGF0c19uYXZfdHJfZGlzdDIsCiAgICAiZGlzdC0zIiA9IHN0YXRzX25hdl90cl9kaXN0MywKICAgICJkaXN0LTQiID0gc3RhdHNfbmF2X3RyX2Rpc3Q0CiAgKSwKICAuZiA9IH50aWR5KC54LCBjb25mLmludCA9IFRSVUUpLAogIC5pZCA9ICJyZWZfY2F0IgopICU+JQogIGNoZWNrX3NpZ25pZmljYW5jZSgpICU+JQogIHNlbGVjdCgtYyhyZWZfY2F0LCBlZmZlY3QsIGNvbXBvbmVudCkpICU+JQogIGtibCgKICAgIGNhcHRpb24gPSBzdHJfYygKICAgICAgIjxjZW50ZXI+IiwgIk5hdmlnYXRpb24gYWNjdXJhY3k6IFRyYW5zaXRpb24gUmVldmFsdWF0aW9uIiwgIjwvY2VudGVyPiIKICAgICksCiAgICBkaWdpdHMgPSAzCiAgKSAlPiUKICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygicmVzcG9uc2l2ZSIpKSAlPiUKICBwYWNrX3Jvd3MoIlJlZi4gQ2F0LiBkaXN0LTIiLCAxLCAyNSkgJT4lCiAgcGFja19yb3dzKCJSZWYuIENhdC4gZGlzdC0zIiwgMjYsIDUwKSAlPiUKICBwYWNrX3Jvd3MoIlJlZi4gQ2F0LiBkaXN0LTQiLCA1MSwgNzUpCmBgYAoKYGBge3IgcGxvdC10cn0KcHJlZGljdF90ciA8LSBleHBhbmRfZ3JpZCgKICBtZWFzdXJlbWVudF9pZCA9IGMoIkQxIiwgIkQyIiwgIkQyYiIpLAogIHNob3J0ZXN0X3BhdGggPSBmYWN0b3IoMjo0KSwKICBzdWJfaWQgPSBOQSwgc3R1ZHkgPSBOQQopICU+JQogIHByZWRpY3RfZ2xtbVRNQihzdGF0c19uYXZfdHJfZGlzdDIpCgpwbG90X25hdl90ciA8LSBuYXZfc3R1ZHkzICU+JQogIGZpbHRlcihtZWFzdXJlbWVudF9pZCAlaW4lIGMoIkQxIiwgIkQyIiwgIkQyYiIpKSAlPiUKICBncm91cF9ieShzdWJfaWQsIG1lYXN1cmVtZW50X2lkLCBzaG9ydGVzdF9wYXRoKSAlPiUKICBzdW1tYXJpc2UoYWNjdXJhY3kgPSBtZWFuKGNvcnJlY3QpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUKICBnZ3Bsb3QoYWVzKHg9c2hvcnRlc3RfcGF0aCwgeT1hY2N1cmFjeSwgY29sb3I9bWVhc3VyZW1lbnRfaWQpKSArCiAgdGhlbWVfY3VzdG9tKCkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAuNSwgbGluZXR5cGUgPSAiZGFzaGVkIikgKwogIGdlb21fZG90cGxvdCgKICAgIGFlcyhmaWxsID0gbWVhc3VyZW1lbnRfaWQpLAogICAgYmlud2lkdGggPSAwLjAxLAogICAgYmluYXhpcyA9ICJ5Iiwgc3RhY2tkaXIgPSAiY2VudGVyIiwKICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjc1KSwKICAgIGRvdHNpemUgPSAxLCBhbHBoYSA9IDAuNSwgY29sb3IgPSBOQSwKICAgIHNob3cubGVnZW5kID0gRkFMU0UKICApICsKICBnZW9tX3BvaW50cmFuZ2UoCiAgICBhZXMoCiAgICAgIHggPSBzaG9ydGVzdF9wYXRoLCB5ID0gZml0LAogICAgICB5bWluID0gZml0IC0gc2UuZml0LCB5bWF4ID0gZml0ICsgc2UuZml0LAogICAgICBjb2xvciA9IG1lYXN1cmVtZW50X2lkCiAgICApLAogICAgZGF0YSA9IHByZWRpY3RfdHIsIGluaGVyaXQuYWVzID0gRkFMU0UsIHNob3cubGVnZW5kID0gRkFMU0UsCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC4yNSksIGxpbmV3aWR0aCA9IDEKICApICsKICBnZW9tX2xpbmUoCiAgICBhZXMoCiAgICAgIHggPSBzaG9ydGVzdF9wYXRoLCB5ID0gZml0LAogICAgICBncm91cCA9IG1lYXN1cmVtZW50X2lkLCBjb2xvciA9IG1lYXN1cmVtZW50X2lkCiAgICApLAogICAgZGF0YSA9IHByZWRpY3RfdHIsIGluaGVyaXQuYWVzID0gRkFMU0UsCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC4yNSksIGxpbmV3aWR0aCA9IDEKICApICsKICBzY2FsZV94X2Rpc2NyZXRlKG5hbWUgPSAiU2hvcnRlc3QgcGF0aCBkaXN0YW5jZSIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoCiAgICBuYW1lID0gIkFjY3VyYWN5IiwgbGFiZWxzID0gc2NhbGVzOjpwZXJjZW50LCBicmVha3MgPSBzZXEoMCwgMSwgMC4yNSkKICApICsKICBzY2FsZV9jb2xvcl9tYW51YWwoCiAgICBuYW1lID0gIk1lYXN1cmVtZW50IiwKICAgIHZhbHVlcyA9IGMoIkQxIj0iI2ZhOWZiNSIsICJEMiI9IiM3YTAxNzciLCAiRDJiIj0iIzIzOGI0NSIpLAogICAgbGFiZWxzID0gYygKICAgICAgIkQxIj0iQmVmb3JlIG92ZXJuaWdodCByZXN0IiwKICAgICAgIkQyIj0iQWZ0ZXIgb3Zlcm5pZ2h0IHJlc3QiLAogICAgICAiRDJiIj0iQWZ0ZXIgcmVldmFsdWF0aW9uIgogICAgKQogICkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKAogICAgdmFsdWVzID0gYygiRDEiPSIjZmE5ZmI1IiwgIkQyIj0iIzdhMDE3NyIsICJEMmIiPSIjMjM4YjQ1IikKICApICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMC4zLCAxLjEpKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICBnZ3RpdGxlKCJOYXZpZ2F0aW9uIGFmdGVyIHRyYW5zaXRpb24gcmVldmFsdWF0aW9uIikKCnBsb3RfbmF2X3RyCgppZiAoa25pdHRpbmcpIHsKICBnZ3NhdmUoCiAgICBoZXJlKCJmaWd1cmVzIiwgc3RyX2MoIm5hdmlnYXRpb25fcmVldmFsdWF0aW9uIiwgIi5wZGYiKSksCiAgICBwbG90ID0gcGxvdF9uYXZfdHIsCiAgICB3aWR0aCA9IDQsIGhlaWdodCA9IDQsCiAgICB1bml0cyA9ICJpbiIsIGRwaSA9IDMwMAogICkKfQpgYGAKCgojIFNlc3Npb24gaW5mbwoKRm9yIHJlcHJvZHVjaWJpbGl0eS4KCmBgYHtyIHNlc3Npb24taW5mb30Kc2Vzc2lvbkluZm8oKQpgYGAKCg==